I’ve been working on making the Javascript for a pretty big Rails app unobtrusive. Chucking everything into application.js as shown in many screencasts with trivial apps has proven to be problematic to say the least. It’s brittle code that could very well infiltrate unintended areas of the site that happen to use the same classes or id’s. Bad juju.

What I find amazing is that Rails hasn’t developed a convention for Javascript.1 I’ll describe some approaches I’ve seen and then the approach I developed.

Namespaces 2

This approach still chucks everything into just one or maybe a few big js files, but uses namespacing to get around the potential conflicts. As far as I can tell, though, this approach requires that the user use the next approach via a helper method.

content_for

This is old news and we use it to great effect, but it has drawbacks because it does not rely on convention over configuration. Also, if you have a few <%= yield :foo %> areas, your actions become a muddle of template code and actual action code. Currently we’re using content_for for a few different areas of the page, and it’s already becoming messy in the actions.

Convention over Configuration 3

# application_controller.rb
before_filter :instantiate_action_javascript
def instantiate_action_javascript
    js_path = File.join(controller_path, "#{action_name}.js")
    @current_action_javascript_path = File.exist?(File.join(RAILS_ROOT, 'public', 'javascripts', js_path)) ? js_path : nil
end

# layout.html.erb
<%= @current_action_javascript_path ? javascript_include_tag(@current_action_javascript_path) : "" %>

The code should speak for itself, but I think that mimicking the structure of the views directory makes the most sense here. With this code, I can create javascript files for each action and have them automatically included in the template. Checking for the existence of the file prevents an unnecessary HTTP request and corresponding 404 error in the Javascript console.


  1. We’re still on Rails 2.3.10, so if this is in Rails 3 (or I’ve simply missed it in Rails 2) please let me know. 
  2. First found this at Toby Hede’s blog via this SO post 
  3. I haven’t seen this anywhere else, but I’m certainly not so clever that I think no one else has thought of it.