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

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 controller. So then the question is what are the best ways for passing controller variables to CoffeeScript or JavaScript assets.

This question has kind of been asked in multiple convoluted forms on the forum, but my point in asking it again is to have a place where all recommendations are gathered together, and the code supplied is simple and readable. Also note that I'm specifically referring to assets and not view response files.


Solution 1:

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

Solution 2:

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.