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.
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:
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
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
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
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
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
config.assets.precompile controls which assets are precompiled when you run the
assets:precompile rake task. By default, Rails only precompiles
application.css (or their coffee, erb, sass, etc. versions). These files are often called application “manifests”, because they will contain a bunch of
@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
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
# 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
Continue reading part 4 of this series: Untangling the Rails Asset Pipeline, part 4: Troubleshooting.