如何通过循环动态设置实例变量?

How to dynmically set instance variable through a loop?

我想根据用户选择的订阅计划在一个页面上有多个 braintree 插件。我希望能够根据单击的内容显示下拉菜单。我在尝试如何在不提前设置令牌的情况下在一页上实现多个插入时遇到问题。我尝试创建一个单击事件函数,但不确定是否正确。

我尝试过:

<% @plans.map do |plan| %>
  <button onclick='braintreeClick()-<%= "#{plan.id}" %>'... > Click </button>
...
<% end %>
<script>
function braintreeClick-<%= plan.id %>() {
  var client_token = "<%= @client_token %>";
  ...
}
</script>

如果我从控制器设置多个标记,我可以在一个页面上有多个表单。

那天晚上我尝试了几种不同的方法,但都失败了,例如:

@plans.map do |plan|
  @client_token_"#{plan.id}" = gateway.client_token.generate
end

并设置令牌:

var client_token = "<%= @client_token_"#{plan.id}" %>";

这会破坏我的应用程序并出现错误:unexpected '=' 在上面那行的控制器中

尝试了其他几种方法,例如:

@client_token(plan.id)

错误:unexpected '('

有没有什么方法可以动态设置我的实例变量或者更好的方法来实现我的 javascript 而无需对 javascript 和 client_token 进行硬编码?

我希望能够在删除或添加订阅计划的情况下动态设置此项。

您要查找的是 instance_variable_set 和类比 instance_variable_get 方法。

在您的情况下设置为:

@plans.each do |plan|
  instance_variable_set("@client_token_#{plan.id}", gateway.client_token.generate
end

然后你读到这个:

var client_token = "<%= instance_variable_get("@client_token_#{plan.id}" %>";

有几种方法,如何做到这一点:

第一个是使用 ruby 方法:instance_variable_setinstance_variable_get:

# set new instance variable
instance_variable_set("@client_token_#{plan.id}", gateway.client_token.generate)

# read the instance variable
instance_variable_get("@client_token_#{plan.id}")

你也可以使用散列,而不是实例变量,这样可能会更好

client_tokens = {}
@plans.map do |plan|
  client_tokens[plan.id] = gateway.client_token.generate
end

# and than read it with
client_tokens[plan.id]

如果你想从更多的地方而不是直接在视图中访问它,你可以将它定义为实例变量@client_tokens = {}


如果你想把它改成完全 JS 的东西。你可以这样做:

<% @plans.map do |plan| %>
  <button onclick='braintreeClick("<%= gateway.client_token.generate %>")'... > Click </button>
...
<% end %>
<script>
function braintreeClick(client_token) {
  ...
}
</script>

您将生成令牌并将其直接放入 braintreeClick 函数调用,现在您根本不必为实例变量或更多 ruby 代码操心。这是比前两个更好的解决方案。


最好的解决方案可能是使用不显眼的 javascript 调用。我不知道你用的是什么JS框架,所以我用jQuery:

来演示一下
<% @plans.map do |plan| %>
  <button class="js-brain-tree-button" data-client-token="<%= gateway.client_token.generate %>" ... > Click </button>
...
<% end %>
<script>
function braintreeClick(e) {
  var $button = $(e.currentTarget);
  var client_token = $button.data("client-token");
  ...
};

$(document).ready(function() {
  $(".js-brain-tree-button").on('click', braintreeClick);
});
</script>

注意:抱歉,如果有错别字或错误,我没有测试代码,但它应该显示概念