Using Rails 3.1, where do you put your "page specific" JavaScript code?

The Asset Pipeline docs suggest how to do controller-specific JS:

For example, if a ProjectsController is generated, there will be a new file at app/assets/javascripts/projects.js.coffee and another at app/assets/stylesheets/projects.css.scss. You should put any JavaScript or CSS unique to a controller inside their respective asset files, as these files can then be loaded just for these controllers with lines such as <%= javascript_include_tag params[:controller] %> or <%= stylesheet_link_tag params[:controller] %>.

Link to: asset_pipeline


For the page-specific js you can use Garber-Irish solution.

So your Rails javascripts folder might look like this for two controllers - cars and users:

javascripts/
├── application.js
├── init.js
├── markup_based_js_execution
├── cars
│   ├── init .js
│   ├── index.js
│   └── ...
└── users
    └── ...

And javascripts will look like this:

// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users

// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Your js code for all pages here
}

// cars/init.js

SITENAME.cars.init = function (){
  // Your js code for the cars controller here
}

// cars/index.js

SITENAME.cars.index = function (){
  // Your js code for the index method of the cars controller
}

and markup_based_js_execution will contain code for UTIL object, and on DOM-ready UTIL.init execution.

And don't forget to put this to your layout file:

<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">

I also think that it is better to use classes instead of data-* attributes, for the better page-specific css. As Jason Garber have mentioned: page-specific CSS selectors can get really awkward (when you use data-*attributes)

I hope this will help you.


I see that you've answered your own question, but here's another option:

Basically, you're making the assumption that

//= require_tree .

is required. It's not. Feel free to remove it. In my current application, the first I'm doing with 3.1.x honestly, I've made three different top level JS files. My application.js file only has

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

This way, I can create subdirectories, with their own top level JS files, that only include what I need.

The keys are:

  1. You can remove require_tree - Rails lets you change the assumptions it makes
  2. There's nothing special about the name application.js - any file in the assets/javascript subdirectory can include pre-processor directives with //=

Hope that helps and adds some details to ClosureCowboy's answer.

Sujal


Another option: to create page- or model-specific files, you could create directories inside your assets/javascripts/ folder.

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

Your main application.js manifest file could be configured to load its files from global/. Specific pages or groups of pages could have their own manifests which load files from their own specific directories. Sprockets will automatically combine the files loaded by application.js with your page-specific files, which allows this solution to work.

This technique can be used for style_sheets/ as well.