Rails 4 Asset Pipeline on Heroku

Last Updated: 23 January 2015

assets rails rails4 rails 4 ruby

Table of Contents

The asset pipeline was introduced into Rails in version 3.1. This article contains information needed to run the asset pipeline in Rails version 4 and above on Heroku. This guide is not comprehensive, please see the Rails Asset Pipeline on Heroku Cedar for help with debugging and troubleshooting. This article adds additional information that is specific to the behavior in Rails 4.

Serve assets

By default Rails 4 will not serve your assets. To enable this functionality you need to go into config/application.rb and add this line:

config.serve_static_assets = true

Alternatively you can achieve the same result by including the rails_12factor gem in your Gemfile:

gem 'rails_12factor', group: :production

This gem will configure your application to serve static assets so that you do not need to do this manually in a config file.

Only generate digest assets

In Rails 3, the version of sprockets used in the asset pipeline would produce a “digest” or a “fingerprint” for an asset and then attach it to it’s file name. For example this file:

app/assets/stylesheets/application.css.erb

When precompiled would become:

public/assets/application-c655834251f73d7714351aa287be8556.css

Where “c655834251f73d7714351aa287be8556” is the “digest” or “fingerprint” generated by MD5. In addition to “digest” file names Rails 3 asset pipeline would produce a non-digest version public/assets/application.css. This was useful for things like sending out emails where the recipient may or may not download the asset in a timely manner.

In Rails 4 sprockets will only produce digest filenames. This means that you must use an ERB helper such as this to reference your assets:

<%= asset_path('logo.png') %>

Make sure to add a .erb extension to any files in app/assets that use an ERB helper. So application.css would need to be application.css.erb.

To get around the “email problem”, sprockets will now keep up to 3 copies of the same modified asset at a time. This also helps with rolling deploys so requests for older assets are still available. Even with this behavior it is recommend you use a CDN to serve your assets.

Caching

Heroku now caches 50mb worth of tmp/cache/assets which is a cache directory for the asset pipeline to store intermediate files. This means that future asset compilations will be faster due to not having to recalculate these files.

This is a difference in Heroku and not in the Rails framework. Rails 3 assets are generated on every deploy as there are several bugs that prevent caching from being used effectively.

Debug output

When $ rake assets:precompile is run in production Rails 4 will now shows debug output while generating tmp files, this does not mean your files end up in /tmp. The files will be copied to their correct locations after they are generated.

Known issues

There are two known issues with Rails 4 (sprockets) that can be difficult to detect or debug. To help with this we recommend using the sprockets better errors gem gem in production. These checks have been merged into Rails 4.1+ but the gem is still needed for 4.0.x versions.

You may get errors if you use sprockets_better_errors with Rails 4.1+.

Dependencies improperly used

You can see a failure in sprockets When you change an asset file that is referenced in another file and the reference does not change. This is due to missing sprockets dependency declarations.

For example you can have a CSS file app/assets/stylesheets/application.css.erb that references another file:

.logo {
  background-image:url('<%= asset_path("logo.png") %> ');
}

Here application.css.erb relies on app/assets/images/logo.png. When precompile is run both assets will be generated. What happens if the logo.png is resized to be larger per a client request? The next time precompile runs, sprockets will see that logo.png has changed since it’s MD5 fingerprint is now different so it will be compiled. Our application.css.erb however has not changed, so it will not be compiled again. This means our stylesheet now points to the wrong copy of our image. To fix this add an asset declaration to the top of your application.css.erb file:

//= depend_on_asset "logo.png"

.logo {
  background-image:url('<%= asset_path("logo.png") %> ');
}

Now when your logo.png changes, your application.css.erb will be required to compile again.

Missing Asset in precompile list

Another common production failure in sprockets is caused by assets not being declared as needing to be precompiled. By default all “application” assets and images are precompiled. This includes application.css and application.js. It is assumed that any CSS or JS in your project will be rolled into these files and so any extra JS or CSS in your project will not be precompiled. The gem sprockets_better_errors will check for missing assets in your precompile list in development.

Debugging

One of the best tools to debug your generated assets is to view them on your dynos:

$ heroku run bash
$ ls public/assets

You should see a manifest-<digest>.json where <digest> is a long alphanumeric string as well as all of your asset files.

You can also see the exact file name that Rails believes it should serve by running $ heroku run rails console. In the console you can use the helper object and asset_path to determine the full path.

$ heroku run rails console
> puts helper.asset_path("application.js")
/assets/application-6aae32862efc758cf08c7b7fc0e85e15.js

Additional troubleshooting

Please see a comprehensive list in the Asset Pipeline troubleshooting section.