Untangling the Rails Asset Pipeline, Part 3
Making sense of the configuration options.
The asset pipeline feature introduced in Rails 3.1 is not so simple once you start tweaking the settings. This article takes a look at some of the trickier aspects of asset pipeline configuration, along with a practical example of testing production settings without a web server.
You’re reading the third installment of a four-part series on the Rails asset pipeline. The previous entries are Part 1: Caches and Compass and Part 2: Production.
Making sense of the asset pipeline-related settings
By default, Rails scatters the configuration of the asset pipeline in a few different places. Also confusing is that sometimes the term “asset” does not refer to the asset pipeline specifically. Finally, many settings are interrelated. Here’s a quick reference to three of the trickiest:
1. config.assets.compile
config.assets.compile
is true
in development and test environments, and is what tells Rails to compile (and cache) the contents of app/assets/
on the fly whenever the browser makes a request for a script or stylesheet. It is false
in production, meaning assets in production must be precompiled.
Furthermore, it is worth noting that Rails does more than just disable compilation in production: by default, some versions Rails (3.1 and 3.2) go one step further and do not even load asset pipeline-related gems in production. This is a nice optimization, but it means that should you ever want to enable asset compilation in production, it is not just a simple matter of setting config.assets.compile=true
.
Most applications will have no reason to do so, but if for some reason you do want to enable asset compilation in production for Rails 3.x, you will need to perform two steps: first set config.assets.compile=true
, then alter the Bundler.require
section in application.rb
:
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
# Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
Bundler.require(:default, :assets, Rails.env)
end
2. config.serve_static_files
config.serve_static_files
is related to the asset pipeline, but more broad: it controls whether or not Rails serves the static files located in the public/
directory. These might be precompiled asset pipeline assets, or they may just be static files you’ve decided to put there, like public/favicon.ico
.
When set to true
, Rails will install a middleware that checks if each browser request matches a file in the public/
directory. If so, it responds with the matching file, and your routes and controllers will not be used. Since this middleware adds a certain amount of overhead to processing each request, it is important to set config.serve_static_files=true
only if necessary.
This setting is true
in development and test environments. In production it is false
, because a web server like Nginx will handle serving public/
files.
3. config.assets.precompile
config.assets.precompile
controls which assets are precompiled when you run the assets:precompile
rake task. By default, Rails only precompiles application.js
and application.css
(or their coffee, erb, sass, etc. versions). These files are often called application “manifests”, because they will contain a bunch of //=require
or @import
statements. Rails will compile these referenced files as well.
But scripts and stylesheets not referenced by these manifests will not be compiled! Consider the case where you have factored legacy Internet Explorer-specific styles into a separate ie.css
file. It is fairly common to link to this in a conditional comment:
<!--[if IE]>
<%= stylesheet_link_tag "ie" %>
<![endif]-->
This will work in development, but when you deploy to production it will fail, because ie.css
will be skipped during assets:precompile
. This is where config.assets.precompile
comes in:
config.assets.precompile += ['ie.css']
Regular expressions are also possible (as explained in Getting Compass to work with Rails):
# Precompile *all* assets, except those that start with underscore
config.assets.precompile << /(^[^_\/]|\/[^_])[^\/]*$/
Testing in production without a web server
As explained in the previous article of this series, normally an asset pipeline-enabled application will not work at all in production without a web server. But what if we want to test an application before the web server is set up? Or maybe we want to run our code in production mode locally without a web server.
The solution is to tell Rails to play the role of the web server, which is to say: serve static files from the public/assets
directory.
Precompile assets as you would normally. Remember, asset pipeline-related code and gems are disabled in production, so we have to compile ahead of time.
bundle exec rake assets:precompile
Tell Rails to serve static files. In production.rb
:
# Serve public/* without a web server
config.serve_static_files = true
Now start your application in production mode:
rails server -e production
Your application is now up and running sans web server; all CSS and JS will be served by a Rails middleware using the precompiled files in the public/assets
directory.
Continue reading part 4 of this series: Untangling the Rails Asset Pipeline, part 4: Troubleshooting.
You just read
Untangling the Rails Asset Pipeline, Part 3
Making sense of the configuration options.
Share this post? Copy link
About the author
Hi! I’m a Ruby and CSS enthusiast, regular open source contributor, software engineer, and occasional blogger writing from the San Francisco Bay Area. Thanks for stopping by! —Matt