Using Controller-specific CSS/JavaScript With Rails Asset Pipeline

While designing my first Rails (3.2) app I found myself wanting to add specific styling and javascript bits to some controllers without affecting others.

I imagined having files named after controllers and make Sprockets automagically include the controller-specific assets based on the context. But how?

Well, we can’t add a require statement to application.css or application.js because that would include the required file for all controllers, and there’s no such thing as a “conditional require”. So how do we do it?

Actually I found out the solution is pretty easy, but there’s a small twist to make it work in production environment.

Assuming you’ll be naming your controller-specific assets something like controller.css.scss and controller.js.coffee, you can include them selectively by adding the two following lines to your applications.html.erb file:

Adding Controller-specific Assets to yout layout - application.html.erb
1
2
<%= stylesheet_link_tag params[:controller] if AppName::Application.assets.find_asset("#{params[:controller]}.css") %>
<%= javascript_include_tag params[:controller] if AppName::Application.assets.find_asset("#{params[:controller]}.js") %>

This works like a charm in development environment, but if you leave it at that and try to use it in production it will fail. It fails because by default Rails does not precompile assets that are not explicitly referenced by a require statement (Read more about that on the Rails Asset Pipeline Guide.)

As it turns out, there’s a config variable you can set in config/application.rb to make Rails explicitly precompile extra assets. You can go ahead and manually add your files to that list:

Manually Adding Extra Assets to Precompile - config/application.rb
1
config.assets.precompile += %w( controller.css )

Hint!

When telling Rails which files you want precompiled, always use the filename the asset will have at the end of the process. So even if you plan to use Sass for a stylesheet and will write a file named controller.css.scss, the file you want to inform Rails is simply controller.css.

Ok. But what if I have a bunch of files? Or what if I don’t even know yet which or how many extra files I want precompiled? Having to name them all is too cumbersome, so we’ll tell Rails which files we want precompiled with a RegExp!

Adding Extra Assets to Precompile with RegExp - config/application.rb
1
2
# Precompile *all* assets, except those that start with underscore
config.assets.precompile << /(^[^_\/]|\/[^_])[^\/]*$/

There it is! So now Rails will precompile all assets, except those starting with an underscore (that way we can even have asset partials), and the solution will work in production environment!

The RegExp is courtesy of Matt Brictson of 55 Minutes. I came across it on a post he made about making Compass work with Rails 3.1/3.2. Apparently you also have to precompile extra assets when using compass. Anyway, thanks Matt!

Comments