Rails: access controller instance variable in CoffeeScript or JavaScript asset file

前端 未结 6 1116
我寻月下人不归
我寻月下人不归 2020-12-01 01:19

In Rails 3.1 it is not possible to access controller instance variables in an asset js.erb or coffee.erb file using syntax such as <%= @foo %>, where @foo is set in the c

相关标签:
6条回答
  • 2020-12-01 01:52

    There is a really nice rail cast and quite recent (feb. 2012) about this specific topic: #324 Passing Data to JavaScript

    It shows 3 ways: a script tag, a data attribute, and the Gon gem. I think house covered all the available techniques. I would only mention that using an AJAX call is best used when you have a large volume of data, dynamic data or combination of both.

    0 讨论(0)
  • 2020-12-01 01:53

    In the controller:

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

    In the view (HAML):

    #foo{@foo_attr}
    

    In the CoffeeScript asset:

    $("#foo").data("foo-1")
    $("#foo").data("foo-2")
    
    0 讨论(0)
  • 2020-12-01 02:03

    You can edit and add variables to the params array in the controller then access them in the response.js.erb. Here's an example with 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
    

    And here's an example accompanying 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 %>
    
    0 讨论(0)
  • 2020-12-01 02:12

    Rather than use a hidden field I chose to add a data attribute to the container div which jquery can pick up.

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

    then the jquery to access it

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

    I feel this is the cleanest way to pass data to javascript. After having found no way to pass a variable to a coffee script file with the rails asset pipeline from a controller. This is the method I now use. Can't wait till someone does set up the controller way with rails that will be the best.

    0 讨论(0)
  • 2020-12-01 02:14

    a couple of ways I have done this in the past

    put the data in hidden fields, access the data in 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")
    

    another option: load data into js data structure in erb, access it from 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}"
    

    I am not a big fan of constructing javascript data from ruby in erb like this, something about it just feels wrong - it can be effective though

    and another option: make an ajax call and get the data on-demand from the server

    I am also interested in other ideas and approaches

    0 讨论(0)
  • 2020-12-01 02:14

    In situations where your javascript data gets out of hand, using the gon gem is still the preferred way to go in rails, even in 2015. After setting up gon, you are able to pass data to your javascript files by simply assigning the data to the gon object in rails.

    (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"}];
    

    You can read more verbose implementation details on Gon or the two other rails-javascript channels from Ryan Bate's screencast.
    http://railscasts.com/episodes/324-passing-data-to-javascript

    0 讨论(0)
提交回复
热议问题