Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量

Posted

技术标签:

【中文标题】Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量【英文标题】:Rails: access controller instance variable in CoffeeScript or JavaScript asset file 【发布时间】:2012-01-20 18:49:19 【问题描述】:

在 Rails 3.1 中,无法使用 等语法访问资产 js.erb 或 coffee.erb 文件中的控制器实例变量,其中 @foo 在控制器中设置。那么问题就是将控制器变量传递给 CoffeeScript 或 javascript 资产的最佳方法是什么。

这个问题已经在论坛上以多种复杂的形式提出,但我再次询问的目的是有一个地方可以收集所有建议,并且提供的代码简单易读。另请注意,我专门指的是资产,而不是查看响应文件。

【问题讨论】:

这是 ***.com/questions/8108511/… 的副本吗?看起来那里接受的答案会有所帮助。 @Thilo 据我了解,该问题是指视图文件夹中的 .slim 模板,因此实际上 CoffeeScript 正在作为视图的一部分而不是预先作为资产文件进行处理。如果我错了,请纠正我。 是的,我对 Rails 不够熟悉,无法确定该答案是否适用。但要点似乎是将您需要的所有实例变量呈现到一段 Javascript 中,然后其他资产可以引用。 在这里会引起争议,问你为什么需要这样的访问权限? 另外,相关问题的第二个答案实际上显示了我认为更好的做法。将您需要的任何数据存储在您真正需要的数据属性中。此外,请考虑使用 JSON 响应从您的 rails 操作请求非 html 模板的任何内容。 【参考方案1】:

我过去做过的几种方法

将数据放入隐藏字段,访问js/coffee中的数据

# single value
<%= hidden_field_tag "foo_name", @foo.name,  :id => "foo-name"  %>
$('#foo-name').val();

# when the 'value' has multiple attributes
<%= hidden_field_tag "foo", @foo.id,  :id => "foo", "data-first-name" => @foo.first_name, "data-last-name" => @foo.last_name  %>
$foo = $('#foo')
console.log $foo.val()
console.log $foo.data("firstName")
console.log $foo.data("lastName")

另一种选择:将数据加载到erb中的js数据结构中,从js/coffee访问它

<% content_for(:head) do %>
    <script>
    window.App = window.App || ;
    window.App.Data = window.App.Data || ;
    window.App.Data.fooList = [
        <% @list.each do |foo| %>
            <%= foo.to_json %>,
        <% end %>
    ];
    </script>
<% end %>


# coffee
for foo in window.App.Data.fooList
    console.log "#foo.id, #foo.first_name #foo.last_name"

我不喜欢像这样从 erb 中的 ruby​​ 构建 javascript 数据,只是感觉有些不对劲——虽然它可能很有效

另一种选择:进行 ajax 调用并按需从服务器获取数据

我也对其他想法和方法感兴趣

【讨论】:

如果您需要运行循环并构造 json,您可以使用 before_filter 运行方法来构造单个 JSON 对象并将其分配给实例变量。然后,您只需在视图的 Javascript 赋值中输出一个实例变量。我发现这比 ajax 更好,因为它减少了一个 HTTP 请求。 第二个选项看起来很不错。必须记住那个。【参考方案2】:

关于这个特定主题,最近(2012 年 2 月)有一个非常好的轨道演员: #324 Passing Data to JavaScript

它显示了 3 种方式:脚本标签、数据属性和 Gon gem。 我认为房子涵盖了所有可用的技术。我只想提一下,当您拥有大量数据、动态数据或两者的组合时,最好使用 AJAX 调用。

【讨论】:

Rudolph,打开 RailsCast,它还会显示代码示例。比我能给出的更好的例子:) 我打开了,我看到了,但答案应该是包含所有相关示例代码的(即要求您访问另一个页面才能获得相关信息) ... 这里提到的技术和在视图中传递变量给Js的技术是一样的:***.com/questions/2464966/… 这是最好的答案。我添加了一个包含使用 gon 的示例的答案,但我的编辑批准率太低,我只是将其作为答案重新发布。【参考方案3】:

我没有使用隐藏字段,而是选择将数据属性添加到 jquery 可以拾取的容器 div。

<div class="searchResults" data-query="<%= @q %>"></div>

然后是 jquery 来访问它

url: "/search/get_results?search[q]=" + $(".searchResults").data("query") + "&page=" + p

我觉得这是将数据传递给 javascript 的最简洁的方式。在发现无法使用来自控制器的 rails 资产管道将变量传递给咖啡脚本文件之后。这是我现在使用的方法。不能等到有人用最好的导轨设置控制器方式。

【讨论】:

【参考方案4】:

在控制器中:

@foo_attr =  "data-foo-1" => 1, "data-foo-2" => 2 

在视图中(HAML):

#foo@foo_attr

在 CoffeeScript 资产中:

$("#foo").data("foo-1")
$("#foo").data("foo-2")

【讨论】:

【参考方案5】:

在您的 javascript 数据失控的情况下,使用 gon gem 仍然是进入 rails 的首选方式,即使在 2015 年也是如此。设置 gon 后,您可以通过简单地分配将数据传递到您的 javascript 文件将数据发送到 rails 中的 gon 对象。

(Gemfile)
gem 'gon'

(controller) 
def index 
  gon.products = Product.all 

(layouts) 
<%= include_gon %> 

(public/javascripts/your_js_can_be_here.js) 
alert(gon.products[0]['id'); 

(html source automatically produced) 
<script> 
  window.gon = ; 
  gon.products = ["created_at":"2015", "updated_at":"2015, "id":1, "etc":"etc"];

您可以从 Ryan Bate 的截屏视频中阅读有关 Gon 或其他两个 rails-javascript 频道的更多详细实现细节。http://railscasts.com/episodes/324-passing-data-to-javascript

【讨论】:

【参考方案6】:

您可以编辑变量并将其添加到控制器中的 params 数组,然后在 response.js.erb 中访问它们。这是params[:value] 的示例:

def vote
  value = params[:type] == "up" ? 1 : -1
  params[:value] = value
  @public_comment = PublicComment.find(params[:id])

  have_voted = @public_comment.evaluators_for(:pub_votes_up) << @public_comment.evaluators_for(:pub_votes_down)

  unless have_voted.include?(@current_user) # vote
    @public_comment.add_or_update_evaluation(:"pub_votes_#params[:type]", value, @current_user)
  else                                      # unvote
    @public_comment.delete_evaluation(:"pub_votes_#params[:type]", @current_user)
    params[:value] = 0
  end

  respond_to do |format|
    format.js # vote.js.erb
  end
end

这是一个伴随 response.js.erb 的示例

button = $('<%= ".pub#params[:type]_#params[:id]" %>')
label = button.find('strong')
<% comment = PublicComment.find(params[:id]) %>
label.html('<%= comment.reputation_for(:"pub_votes_#params[:type]").to_i %>')

<% if params[:value] == 1 %>
  button.addClass('btn-success')
<% elsif params[:value] == -1 %>
  button.addClass('btn-danger')
<% else %>
  if button.hasClass('btn-success')  button.removeClass('btn-success') 
  if button.hasClass('btn-danger')  button.removeClass('btn-danger') 
<% end %>

【讨论】:

以上是关于Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量的主要内容,如果未能解决你的问题,请参考以下文章

是否/为啥 Rails 6 仍在使用/推荐 CoffeeScript?

Rails 啥时候编译 CoffeeScript?

导轨 3.1。如何防止 Rails 使用 CoffeeScript?

Rails - 从 JavaScript 调用 CoffeeScript

如何在 Rails 3.1 应用程序中完全禁用 CoffeeScript?

Rails 3.1:我需要使用 CoffeeScript 吗?