September 23, 2014 - No Comments!

Stop Missing Files in Your Assets Precompile

Rails Asset PrecompileWell, it’s been a good couple of days. You’ve been productive and finally released that tricky feature. It got pretty complicated, but you knew this was happening and were super careful to test along the way. A lot of the work was done in a new JavaScript file you added to your Rails project. Everything is working well for the team testing this locally (and we tested this thing upside down and inside out). Excellent. Now, it’s time to get this in front of your client. Time to push this new stuff to the server. Deployment successful and the fancy new thing you just built isn’t working. Sounds familiar doesn’t it?

We recently had this happen to us again. We added a JavaScript file, and forgot to add the JavaScript file to the `assets.precompile` list. The problem is pretty obvious once you realize what’s happening. And we should point out that this is likely something that you'll hit when you're updating older projects as the new strategy doesn't become default until Rails 4.1. Ok, let’s figure out what’s going on and talk about a solid resolution to the problem.

Once we’d figured it out , we could have just added it to config/environments/production.rb:

config.assets.precompile += %w( application-*.js )

to

config.assets.precompile += %w( application-*.js notes.js )

While that does work, we don’t want to have to remember to make this change every time we add new files. Happily, we found a new feature in Rails 4: the ability to add runtime errors in development if the asset pipeline settings are incorrect.

In Rails 4, the default generated development.rb file has the following settings:

# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true

In order to use the raise_runtime_errors feature, we also had to move our assets declarations from production.rb to config/initializers/assets.rb :

Rails.application.configure do
  # Precompile additional assets.
  # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
  config.assets.precompile += %w( application-*.js )
  config.assets.precompile += %w( notes.js )
end

This way, the assets.precompile settings are always specified (not only for the production environment, but for development and test environments also).

With the raise_runtime_errors = true set in development.rb we will see an error if we try to browse to a page which references a file which is not specified in the assets pipeline. But this isn’t enough for us. We also want our automated tests to fail so we also set the config.assets.raise_runtime_errors = true in our test.rb environment. That will make our test suite will fail.

Running the tests now, we get the error message:

Failure/Error: before { visit write_note_path }
   ActionView::Template::Error:
     Asset filtered out and will not be served: add `Rails.application.config.assets.precompile += %w( notes.js )` to `config/initializers/assets.rb` and restart your server

Adding notes.js to the precompile list resolves the issue, and the tests pass again.

With this in place, we think we have eliminated one more possible mistake from our development process.

Aside: During our research and testing of the raise_runtime_errors feature, we were confused for a while because the rails documentation says:

By default the asset pipeline will check for potential errors in development mode during runtime. To disable this behavior you can set:

config.assets.raise_runtime_errors = false

We assumed that ‘by default’ meant that if we didn’t specify any settings in our file, the raise_runtime_errors setting would be enabled.

This isn’t actually true. What the documentation means is that if you create a new Rails 4 project, the generated development.rb file will contain the config.assets.raise_runtime_errors. = true statement.

This caused some confusion, but we prevailed.

Published by: Robin Dunlop in Developers

Leave a Reply