Rails: access controller instance variable in CoffeeScript or JavaScript asset file
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.
Solution 3
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.
Solution 4
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")
Solution 5
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
Safa Alai
Updated on February 19, 2020Comments
-
Safa Alai about 4 years
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.
-
BradGreens almost 11 yearsIf you need to run loops and construct json you could use a before_filter which runs a method to construct a single JSON object and assign it to an instance variable. Then you simply output the one instance variable in your view's Javascript assignment. I find this better than ajax because it's one less HTTP request.
-
Max almost 11 yearsRudolph, open the RailsCast and it also shows code examples. Better examples than I could ever give :)
-
rudolph9 almost 11 yearsI opened, I saw, but answers are supposed to be self contained with all pertinent example code (i.e. not require you to access another page in order to get pertinent information)...
-
Ciro Santilli OurBigBook.com over 9 yearsThe techniques mentioned are the same as those for passing variables to Js in views: stackoverflow.com/questions/2464966/…
-
Ninjaxor about 9 yearsThis was the best answer. I added an answer that included examples using gon, but my edit approval rating is so low I just reposted it as an answer.
-
Daniel Viglione about 8 yearsThe second option looks really good. Have to remember that one.