Sprockets, and obviously the sprockets-rails gem received new versions. This means for us here at work that we need to upgrade the gems and make sure the application is still working with the changes.

For most gems, the upgrade procedure would be rather simple:

  1. Update your Gemfile
  2. Run the bundler update command
  3. Runs the specs and deploy when it all passes.

For us, the upgrade was not so simple…
After upgrading the gems, I ran our RSpec suite and was greeted by the following errors all of a sudden:

  8) Admins::WhiteListedIpsController#new authorized properly renders the view
     Failure/Error: <%= javascript_include_tag :application, :admin, :map %>
     
     ActionView::Template::Error:
       The asset "application.js" is not present in the asset pipeline.

Running the application locally in development mode produced no errors whatsoever. Every page, function, call and plugin was properly working under the new Sprockets version, yet when running the test suite with RSpec it suddenly broke.

My first assumption was that there was a conflict with RSpec and the new Sprockets, but that was soon dismissed as there nothing obvious pointing in that direction, and running the suite multiple times produces errors for different assets missing, depending on which spec was running first.

So what was the problem?

In an older version of Sprockets, it was a bad thing to have the compile environment enabled during tests. So in our config/environments/test.rb we had the following line of code written:

# Sprockets whines if this is enabled in tests
config.assets.compile = false

Letting my brain go back in time, I tried to remember where this came from, and when I checked the git logs, we had this enabled for a very old version of Sprockets. Now with the recent upgrade, this is no longer required at all, and because we have run into problems in the past with missing assets, we actually changed our approach:

  • We want Sprockets to tell us when something is not in the pipeline, regardless of the env
  • We want tests to detect problems for production, so the env should be the same
  • We use an initializer to load all assets properly

The solution: We removed that one line from the environment initializer, and everything worked like a charm again.

How did I figure this out?

I actually spent an hour or so looking thorugh all the various settings and playing around with the initializers as well as some configuration changes. Nothing really produced anything that seemed like it would solve our problem. Often I received the error that an asset was not in the pipeline, despite being explicitly written inside the initializer.

A lightbulb began to burn when one of the errors complained about the application.js not being in the pipeline. That was something not really possible, as this is loaded by default in the Rails framework.

So after reading the documentation of sprocket-rails once more:

config.assets.compile

Enables Sprockets compile environment. If disabled, Rails.application.assets will be nil to prevent inadvertent compilation calls. View helpers will depend on assets being precompiled to public/assets in order to link to them. Initializers expecting Rails.application.assets during boot should be accessing the environment in a config.assets.configure block. See below.

config.assets.configure

Invokes block with environment when the environment is initialized. Allows direct access to the environment instance and lets you lazily load libraries only needed for asset compiling.

config.assets.configure do |env|
  env.js_compressor  = :uglifier # or :closure, :yui
  env.css_compressor = :sass   # or :yui

  require 'my_processor'
  env.register_preprocessor 'application/javascript', MyProcessor

  env.logger = Rails.logger
end

It all became clear:  Our compile was disabled for some reason, and looking at the environment file our test environment revealed the culprit.

But what about the images?

Well, they seem to be broken right now. Shortly after writing this post, I found a problem with images inside RSpec and the test environment not being loaded. I’ve opened a bug report with sprockets-rails: https://github.com/rails/sprockets-rails/issues/379

Basically, what I did to make it work again is add the following snippet for now in our assets initializer:

# HACK: Add all images from our asset folders
#
# For some reason, Sprockets is not loading the images by default into the path.
# This hack adds all .png and .gif images to the initializer so they are part of the pipeline.
# Bug is opened to address this issue: https://github.com/rails/sprockets-rails/issues/379
#
%w(app vendor lib).each do |folder|
  folder_path = Rails.root.join(folder, 'assets', 'images')

  %w(*.png *.gif).each do |extension|
    full_path = File.join(folder_path, '**', extension)

    Dir.glob(full_path).each do |entry|
      if entry.end_with?(extension.gsub('*', '')) # Kick out . entries
        Rails.application.config.assets.precompile << entry.gsub(folder_path.to_s + '/', '')
      end
    end
  end
end

As soon as I receive feedback from the gem maintainers, I will alter our code to get rid of the problem.

Advertisements