Wednesday, March 14, 2012

Rails - How to compile and commit assets locally

The Rails asset pipeline has one major drawback: if you have a large number of assets it can take many minutes to compile these during deploy. The worst I've heard of is 6 minutes! If you deploy frequently this can be a major nuisance.

One answer to this problem is compile within your development environment, commit the files to source control, and deploy them along with the rest of the code.

There is one major issue with this approach; these files will be served by the development web server instead of the requests being handled dynamically by Rails & Sprockets. That stops changes to the underlying assets showing on the front-end.

This is very simple to fix.

In development.rb place the following line:

config.assets.prefix = "/dev-assets"

This over-rides whatever is set in application.rb (normally "/assets").

You will also need this in application.rb:

config.assets.initialize_on_precompile = false

That stops the task trying to connect to your database. (Beware if you are referring to ActiveRecord models in your assets, as this won't work).

These changes allow you to compile and commit the assets to your repository locally, and have those files in your working development tree, but for development requests to still be sent to Sprockets. Plus, you only have to precompile and commit when something has actually changed.

NB: You will need to make sure any Javascript and CSS compressors you use are available on your local machine. And you will need to change the deploy task to NOT precompile assets or create an 'assets' symlink.


Onno Faber said...

We are currently doing this because of this problem, to precompile, tar, upload untar and clean:

run_locally "bundle exec rake assets:clean && bundle exec rake assets:precompile"
# tar the assets to make uploading faster
run_locally "cd public && tar cfz assets.tar.gz assets && cd .."
upload "public/assets.tar.gz", "#{shared_path}/system", :via => :scp, :recursive => true # uploads the folder assets into the system folder
# untar the assets on the remote server
run "cd #{shared_path}/system && tar xvfz assets.tar.gz && rm assets.tar.gz"
run_locally "bundle exec rake assets:clean"
run_locally "rm public/assets.tar.gz"

Anonymous said...

You should probably credit the Rails documentation, given that this is a complete copy of the 4.2 Local Precompilation section:

Richard Hulse said...

And the reason for that is that I made significant contributions to those docs, including that section *after* I wrote this post :-)