We're hiring!

Sass production woes in Rails

by ari on March 20, 2008

Rails 2.0+ introduced our team at CitrusByte to a Sass woe: our sass file would not regenerate. We would be able to regenerate it when ssh’ing into the site and starting the server in an environment other than production. Obviously not an ideal solution. So, what’s the fix?

Place the following in any ruby file in your rails_root/config/initializers/some_file.rb:

p "** Ensuring the Sass::RAILS_LOADED is undefined for regeneration"
if defined?(Sass::RAILS_LOADED)
  module Sass
    remove_const("RAILS_LOADED")
  end
end

Here’s a technical description of the problem:

In Rails, Sass runs through the ActionController::Base.process command with an alias_method. The update_stylesheets method is never surfaced outside of there in the Rails environment; this makes it difficult to run it in a Capistrano task.

Also, the Sass file needs to be regenerated after the plugins load. It’s not ideal to place this in the environment.rb, because most of this runs before other configuration parameters. The initializers load after the plugins load and is the final block of code that is run on the init block. That makes an initializer a perfect place to put our fix.

{ 7 comments… read them below or add one }

Nathan Weizenbaum 03.20.08 at 5:47 pm

The issue here is that Sass stylesheets take a long time to generate, and there’s some overhead for just checking if they need to be regenerated. Thus, in production mode the default is to never check for regeneration except during server startup.

There are a couple easy ways around this. First, you could manually call Sass::Plugin.update_stylesheets. Here’s a Capistrano task that should work for it (hoping this is the right code block formatting):

desc “Update Sass stylesheets” task :sass do run “cd #{releasepath} && ruby -rconfig/environment -e ‘Sass::Plugin.updatestylesheets’” end

A better way, if you want Sass to check to see if updates need to be run for each request, would be to configure Sass in environment.rb:

Sass::Plugin.options[:always_check] = true

——-
Okay, no code formatting, I guess. Here’s a pastie of that cap task: http://pastie.caboo.se/168250.

Ari 03.20.08 at 5:47 pm

Problem is that the always check will cause the check to run, which is still not ideal. Problem with rails 2.0 is that the Sass: :RAILS_LOADED constant is set when it gets to the gem.

You can do it either with that cap task or by unsetting the constant. Otherwise, you still incur that overhead during the runtime.

This way, you get the best of the development environment while maintaining the production-ready environment

Nathan Weizenbaum 03.21.08 at 5:47 pm

I guess I’m misunderstanding the problem. If the issue isn’t getting Sass to regenerate the CSS files when they change, what is it?

Also, I’d advise against undefining Sass::RAILS_LOADED to fix this problem. That constant is an implementation detail; it’s possible that it will change or mean something different in future releases.

Geoff 03.21.08 at 5:47 pm

I don’t quite think I understand the problem here. Are you consistently changing your SASS file on the production server? Surely you’d be better making your changes, testing those changes, committing to version control and then deploying the latest changes to your production server. Restarting the application server on the production server would be done as part of the deployment process.

Josh Adams 07.17.08 at 5:47 pm

Ari,

My only change to your suggestion would be to use ‘latest_release’ a la http://pastie.org/235754

Chu Yeow 08.07.08 at 11:46 am

“Thanks for pointing this out! I’ve been puzzling over this for awhile and with ideas from your blog post and everyone’s comments, arrived at manually generating the stylesheets after each deploy. I have a rake task with this task: namespace :sass do desc ‘Updates stylesheets if necessary from their Sass templates.’ task :update => :environment do Sass::Plugin.update_stylesheets end end And have a cap task mirroring this that is called “after ‘deploy’”: 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) after each deploy. after ‘deploy’, ’sass:update’ end “

Zeke Sikelianos 06.29.09 at 9:46 pm

Thanks for sharing. The Sass::RAILS_LOADED initializer fix worked just fine for me.

Leave a Comment

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>