A few days ago I noticed that some of the pages on the Hotels app on wego.com were completely unstyled. They turned out looking rather Jakob Nielsen-istic:

Wego.com Hotels - no CSS


But we were attached to our ugly shade of green to leave those pages in their naked glory. Preliminary CSI work told me that some cached stylesheets generated by Rails were empty files. Why is this is happening?

stylesheet_link_tag and the :cache option

Was I overriding the stylesheets generated by Rails in different pages? Because we have a lot of cobranded sites and country sites on wego.com, I use the :cache option when using stylesheet_link_tag very often.

For example, the main wego.com site's layout template has a stylesheet_link_tag like this (in reality there are a whole lot more stylesheets):

<%= stylesheet_link_tag 'yui/reset-fonts', 'search',  :cache => 'cache/search/listings' %>

When I need to make a new page for a cobranded site, I'll create a new layout template with this:

<%= stylesheet_link_tag 'yui/reset-fonts', 'search', "sites/#{current_site}/cobrand", :cache => "cache/#{current_site}/search/listings" %>

Oftentimes I'd copy and paste (boo and hiss all you want!) the stylesheet_link_tag from one layout template to another and forget to update the cache path (the :cache => '/path/to/stylesheet' part). Two different stylesheet sets being cached to the same path is naturally a very stupid thing to do. So this wasn't it, but it's good to point this out because I have made this mistake at least 2 times!

Don't check in generated CSS files by accident

Next, since I was using Sass, I was by now pretty sure that was it. First things first: did I check in a generated CSS file into source control (we use Git)? It's another amateur mistake, but unsurprisingly, I've done this a couple of times. I think I'd wasted about an hour hunting down the reason for a style change that just wouldn't show up. Yeah, I could have just added *.css to .gitignore, but I'm still using a mix of pure CSS and Sass templates.

The problem

In the end, I found this blog post by Ari Lerner on the CitrusByte blog about similar woes with Sass in production that set me on the path to a solution. It seems that when Rails encounters stylesheet_link_tag calls, it starts to pull together all the stylesheets and sometimes Sass is unable to generate the CSS files fast enough. Rails then throws an exception about not being able to find the CSS files and outputs an empty CSS file to the cache path.

The solution

The solution? Generate all the CSS files from Sass templates prior to restarting Rails when deploying. I added a rake task for updating all the Sass stylesheets:

namespace :sass do
  desc 'Updates stylesheets if necessary from their Sass templates.'
  task :update => :environment do
    Sass::Plugin.update_stylesheets
  end
end

Then, I created a mirror of this as a Capistrano task:

namespace :sass do
  desc 'Updates the stylesheets generated by Sass'
  task :update, :roles => :app do
    invoke_command "cd #{latest_release}; RAILS_ENV=#{rails_env} rake sass:update"
  end

  # Generate all the stylesheets manually (from their Sass templates) before each restart.
  before 'deploy:restart', 'sass:update'
end

Now, whenever I do a cap deploy, the stylesheets are generated before the Rails processes are restarted, ensuring that Rails' stylesheet_link_tag helper is always able to find the pure CSS files when trying to merge them together and caching them to a single file.