Using Rails data in javascript is a very common need, especially for SPA (Single Page Application) with AngularJS, Backbone.js, Ember... or only pure javascript applications.
We have some ways to make this
Assign to javascipt variable in views
#/views/layouts/application.html.erb
<script type="text/javascript">
var g_currentUser = <%= raw current_user.to_json %>;
</script>
Will render
<script type="text/javascript">
var g_currentUser = {"id":1,"email":"[email protected]","created_at":"2015-02-01T07:46:33.303Z","updated_at":"2015-02-01T07:58:16.516Z"};
</script>
g_currentUser is global variable, so we can use it in javascipt files.
Render data to "data" HTML attribute
<%= content_tag(:span, id: 'initial-vars', class: 'invisible', data: {current_user: current_user}){} %>
Will render
<span id="initial-vars" class="invisible" data-current-user="{"id":1,"email":"[email protected]","created_at":"2015-02-01T07:46:33.303Z","updated_at":"2015-02-01T07:58:16.516Z"}"></span>
Then
var g_currentUser = $('span#initial-vars').data().currentUser;
Use Gon
Above solutions seem to be not very clean and manageable, especially when we need more data instead of only g_currentUser
.
Gon helps us to archive our need easier and cleaner.
Setup
Setup gon
is easy
- Add
gem 'gon'
to Gemfile and runbundle install
- Insert
<%= include_gon %>
inhead
tag of layouts (you can bring it to anywhere you want to use it if you don't want Gon available in all views. Actually, put it in layout is the most case)
Set variables from controller/view (often from controller)
gon.currentUser = current_user
gon.siteName = 'Awesome Site'
# OR
gon.push({
currentUser: current_user,
siteName: 'Awesome Site'
})
Use it in javascript
Above code will generate this in rendered page
//<![CDATA[
window.gon={};gon.currentUser={"id":1,"email":"[email protected]","created_at":"2015-02-01T07:46:33.303Z","updated_at":"2015-02-01T07:58:16.516Z"};gon.siteName="Awesome site";
//]]>
So, in javascript we can use them as normal variables
console.log(gon.currentUser);
console.log(gon.siteName);
Output
Object {id: 1, email: "[email protected]", created_at: "2015-02-01T07:46:33.303Z", updated_at: "2015-02-01T07:58:16.516Z"}
Awesome site
Tips
- Use
<%= include_gon(namespace: 'App') %>
instead of<%= include_gon %>
to useApp.currentUser
instead ofgon.currentUser
- Include Gon in
body
instead ofhead
when usingturbolinks
to make Gon reload in each pave moving - Gon be be used with Rabl, see Guide
- Gon be be used with JBuilder, see Guide
- Use gon.watch to reload Gon variables from Rails asynchronously
- Gon will cause
gon is not defined
javascript error if no variable was pushed to Gon. Always push atleast 1 variable to Gon to prevent this - See Gon Wiki for more information