How to Pass Data From Rails to Javascript / Coffeescript

If you want to pass data between Rails and Coffeescript in your apps, you'll find that interpolation doesn't work. For example:

# app/assets/javascript/home.coffee
$ ->
  $('#some_element' ).text('<%= @user.id %>')

If you look at the resulting Javascript, you'll see that the string is interpreted literally, rather than interpolating the user's id:

(function() {
  $(function() {
    $('#some_element' ).text('<%= @user.id %>');
  });
}).call(this);

Quickfix

You can quickly fix this by appending .erb to the Coffeescript's filename. This will instruct the asset compiler to parse the file through ERB before Coffeescript, resulting in the value being correctly interpolated:

# app/assets/javascript/home.coffee.erb
$ ->
  $('#some_element' ).text('<%= @user.id %>')
// (resulting Javascript)
(function() {
  $(function() {
    $('#some_element' ).text('32');
  });
}).call(this);

A More Flexible Approach

However, I feel this too tightly-couples the Javascript and Rails code. I much prefer to follow Rails' own unobtrusive-Javascript approach, and make use of HTML5 data attributes to pass data between the front-end (JS) and back-end (Rails) code.

Using the example above, the id would be passed as an arbitrary data attribute on the HTML element:

# app/views/home/index.html.erb
<div class="user-details" data-user-id="<%= @user.id %>">
</div>

Now in the Javascript, you can easily extract the value of data-user-id. Furthermore, you can use the same code to act on any HTML element containing the data attribute:

# app/assets/javascript/home.coffee
$ ->
  $('div[data-user-id]' ).each ->
    userId = $(this).data('user-id')
    $(this).text(userId)

This post was inspired by a question on StackOverflow. See the original discussion.