A problem commonly faced by Rails developers is how to organize and include Javascript on pages so no extra code is run. Here’s an approach to make page specific Javascript easy.

By default, the asset pipeline is setup to serve one javascript file for each app. If you generate a controller using rails g controller NAME, a corresponding javascript file is added to app/assets/javascript/NAME.js. These files are included using the require directives in app/assets/javascript/application.js. For the most part this approach works.

It does however, have a couple drawbacks. You either have to embrace that your jQuery selectors will run on every page, or you will need to add if-statements to your code to test for the presence of an element with the selector before you execute the code. This can lead to some pretty messy files and might hurt performance if you have a lot of separate Javascript functions to run.

What if you could run only the javascript you need to run on each page? If you could, you can remove all the existence checks and ensure only the code you want executes.

Enter SeedTray. SeedTray is a convention-based approach to page specific Javascript. It’s straight forward to setup.

Add the gem to your Gemfile:

gem 'seed_tray', '~>0.1.2'

Require seed_tray in your application.js file:

//= require jquery
//= require jquery_ujs
//= require turbolinks
...
//= require seed_tray

Add page_data_attr to your layout’s <body> element. This adds data attributes that allow SeedTray to identify which page is one.

<body <%= page_data_attr %> >
...
</body>

Next, add a few Coffeescript classes. You need to add a class with the same name as your Rails app. For example, if our app was called TodoList, we need to define:

class @TodoList

This class serves are the root namespace for your page specific Javascript. For each controller you add a corresponding class. For example, if we had a controller called TodosController with actions index and show, we add to todos.js.coffee:

class @TodoList.Todos

class @TodoList.Todos.Show

class @TodoList.Todos.Index

In each class we add a method named ready, which defines what we want to run on that view. SeedTray will call this method automatically when the view is rendered.

class @TodoList.Todos
  @ready: ->
    #code to run on all todos views

class @TodoList.Todos.Show
  @ready: ->
    #code to run on the show view

class @TodoList.Todos.Index
  @ready: ->
    #code to run on the index view

Tada! You have page specific Javascript!