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

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

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

【问题讨论】:

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

标签: ruby-on-rails controller coffeescript erb instance-variables


【解决方案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的技术是一样的:stackoverflow.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 %>
        

        【讨论】:

          猜你喜欢
          • 2018-08-16
          • 2012-12-06
          • 1970-01-01
          • 2023-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-11
          相关资源
          最近更新 更多