我目前非常精通Ruby和JS,并开始使用Rails。我已经创建了一个最小的Rails应用程序,我正在从JavaScript事件处理程序(按钮单击事件处理程序)调用Ruby方法。该方法应该对一组卡片进行采样并显示结果。
我通过发出这些命令创建了应用程序:
rails new blackjack
cd blackjack
bin/rails generate controller Games blackjack
rails s
我在这里提到了两个文件:./app/views/games/blackjack.html.erb
和./app/controllers/games_controller.rb
。下面是这两个文件中的代码:
games_controller.rb
class GamesController < ApplicationController
def blackjack
@game = Game.new
end
end
class Deck
CARD_VALUES = {
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'10' => 10,
'J' => 10,
'Q' => 10,
'K' => 10,
'A' => 11
}.freeze
RANKS = %w(2 3 4 5 6 7 8 9 10 J Q K A).freeze
# UTF codes for suit symbols
SUITS = ["\u2660", "\u2661", "\u2662", "\u2663"].freeze
attr_reader :cards
def initialize
new_deck
end
def new_deck
@cards = RANKS.product(SUITS).shuffle
end
end
class Game
attr_reader :deck
def initialize
@deck = Deck.new
end
end
二十一点.html.erb
<p id="card" style="font-size:48px">Card: <%= @game.deck.cards.sample %></p>
<button id="button-card">Card</button>
<script>
document.getElementById('button-card').addEventListener('click', e => {
let card = `<%= @game.deck.cards.sample %>`;
card = card.replace(/"/g, '"');
document.getElementById('card').innerText = 'Card: ' + card;
});
</script>
发生的情况是这样的。当我打开页面时,当第一行的#sample
方法被调用时,它会显示一张随机卡片,例如["6", "♢"]
。这与我预期的一样。当我单击Card
按钮时,我会得到另一张随机卡片,也与我预期的一样。但是当我再次单击Card
按钮时,或者任何次数,卡片保持不变。我已经确定,每次单击Card
按钮时,都会调用click
处理程序中的sample
方法,但相同的卡片值不断插入到p
标记中。此外,如果我重新加载页面,我会得到一张新卡片。
所以,我可能忽略了一些基本的东西,关于嵌入式Ruby如何在客户端与JavaScript一起工作。
我确信这不是一种传统的在Rails中做事情的方式,但是我试图更好地理解嵌入式Ruby在Rails中是如何工作的。有人能启发我吗?
1条答案
按热度按时间hgqdbh6s1#
这个问题与ERB无关,它只是另一个模板引擎。
问题是Turbo创建了一个跨页面的持久会话(就像许多现代的javascript框架一样),并且像这样编写非幂等的代码在今天是不会解决这个问题的。无论你在后端使用什么语言,你都会遇到同样的问题。
脚本标签的情况是,每次Turbolinks访问页面时,它都会重新评估。事件处理程序将彼此堆叠,最后一个获胜。这会产生典型的“但是哇!当我重新加载页面时,它会工作!”场景。
相反,只需在外部脚本中创建委托幂等事件处理程序:
由于事件处理程序是绑定到文档而不是单个元素的,所以即使在页面访问时也可以这样做,而且正如您所看到的,您的脚本中不需要ERB插值。
支持Turbo的Stimulus.js library基于相同的基本原理工作-委托事件处理程序和数据属性作为传递状态的方法。
如果你真的想继续用ERB将数据插入JS的死胡同,你至少需要确保删除任何以前的事件处理程序,这样你的脚本的效果就不会叠加。