Rigel Group

They shoot Yaks, don't they?

Page-Specific Javascript Using Coffeescript

Rails apps that take advantage of the asset pipeline typically have all their javascript files packaged up (and perhaps minified) into one file, mainly for performance reasons. So that means every page in your app loads all the javascript, and you are left with figuring out some way to have some specific javascript code run only on a specific page. There are loads of techniques out on the net that accomplish this, but here is another one we came up with, which leverages the beauty of Coffeescript. If you are not a fan, stop reading now.

OK, you’re still here, which means you are not averse to some Coffeescript, so lets get started. The first thing we do is create a Base class that will house all code that should be run on every page.

1
2
3
4
5
6
7
8
9
10
11
window.MyApp ||= {}
class MyApp.Base

  # Rails server code can pass in some bootstrap data if necessary, which we will save off for use anywhere on the client
  constructor: (bootstrap_data={}) ->
    @bd = bootstrap_data
    # Put your general code here. Don't worry about document ready since this
    # code will only be called once the document is ready

    # MAKE SURE YOU RETURN this
    this

Next, create a class for each Rails Controller, so for example if we have a Posts Controller in our app, we would create this Coffeescript class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.MyApp ||= {}
class MyApp.Posts extends Base

  constructor: () ->
      # By calling super, we make sure that all the code in the Base class constructor gets run
    super

    # Your code goes here that should run on every page of the Posts controller, regardless of the action

    this


  index: () ->
    # Code that should run ONLY for the index action

  show: () ->
    # Code that should run ONLY for the show action

So, once you have all your Coffeescript files all bundled up and served to the browser in one large bunch, how does the browser know which code to run? We just have one more thing to do, and that is put this snippet of javascript in a script tag in your Rails layout file:

1
2
3
4
5
6
jQuery(function() {
  window.$M = new (MyApp[<%= params[:controller] %>] || Kaleo.Base)(@bootstrap_data);
  if (typeof $M[<%= params[:action] %>] === 'function') {
    return $M[<%= params[:action] %>].call();
  }
});

Like anything in software, there are many ways to do this, the above uses ERB snippets to inject the controller and action names into the javascript code. If your action sets the @bootstrap_data variable to some json, that will get passed into the Coffeescript classes we made above. The shortcut variable $M is created that gives you access to the class that was created, so you can get the boostrap data with $M.bd.