Ruby On Rails 3.1: Upgrading To The Asset Pipeline


rails3 asset pipelineShortly after making the big leap from Rails 2.2.2 to 3.0.10 Rails 3.1 came out. Feeling defeated in my quest to have mightyvites.com on the latest stable release I started down the path of upgrading to 3.1.3. Replacing 3.0.10 with 3.1.3 was actually simple: just change the rails version in my Gemfile and “bundle update rails”. After that it was trivial to get my tests running without error and essentially be upgraded.  However, that wasn’t the goal. Rails 3.1 is all about the asset pipeline and I wanted the concatenation, minification, and cache busting that it brings to the table.

What’s the asset pipeline?

In a nutshell, the asset pipeline brings production-release processing of JavaScript, CSS stylesheets, and images to the Rails core. With the help of the Uglifier and Sprockets gems JS & CSS are stripped of white space and comments, variable name simplified, and stitched together into one big download (one for JS, one for CSS). Asset files are named with a MD5 hash of the file to ensure that returning browsers download any new asset change.

Benefits of using the asset pipeline

So why do you want this feature? Because it optimizes your web app’s front end for delivering a rich client-side experience. By stripping away unnecessary bytes your assets become smaller and take less time to download. By concatenating all JavaScript in one big file and all CSS in another the browser only has two downloads to worry about and not many (same reason we use image sprites). By naming files with a hash of their data file names are sure to change whenever the data changes, forcing revisiting browsers to download the change and not rely on an out-of-date cache.

Working with the asset pipeline

I’m not going to get into how to enable the asset pipeline on a Rails 3.1 app. There is a good Rails Guide to help with that. Instead I want to talk about an issue that I ran into but couldn’t find documented anywhere: once I had the asset pipeline properly enabled my site looked, and behaved, like crap. Why? Because I liked to break my assets into multiple files. I actually had a home grown system that auto-included assets whose filenames were based on the name of the controller and action that served a request. This led to many asset files, each tailored to a specific page, and each included only on the page they were meant for. That common, “old school” approach did not work well out of the box with the new pipeline. Moving all existing assets into the app/assets directory and letting Sprockets compile them made all hell break loose because the result is that every page included all known JS & CSS. There was no more page scoping. CSS cascades were ruined, and JS meant for one page reacted on different pages because the DOM was similar. The result was a total friggin’ mess that I had to resolve without rewriting all my assets.

Scoping CSS for inclusion on the asset pipeline

Carefully crafted, browser tested CSS was by far my biggest concern. There was no way I was going to lose the hours that went into making it work. Luckily a new addition to the Rails 3.1 core helped tremendously: SASS a.k.a. syntactically awesome stylesheets. The name says it all. SASS is everything us old time web devs have wanted CSS to be but that the W3C drags its feet on. For my task the biggest win provided by SASS was nested rules. That let me turn CSS that looked like this:

1
2
3
4
5
   .featured {
      float: left;
      margin-left: -5.75em;              
      padding: 2em .75em 0 .75em;      
   }

into this:

1
2
3
4
5
6
7
8
9
   body.home {
      &.index {
         .featured {
            float: left;
            margin-left: -5.75em;              
            padding: 2em .75em 0 .75em;      
         }
      }
   }

Remember, I was including my asset files based on the name of the controller and action that served a request. The asset pipeline made that impossible because all CSS is in one file. My solution was to continue scoping by controller and action name by including those names in the body element’s class attribute. I then used SASS’ nested rules to wrap existing CSS in the new body classes. The result is what you see above — page scoped CSS that plays well in a single file.

Scoping JavaScript for inclusion on the asset pipeline

Once I figured out how to handle my CSS, JavaScript was a cinch. I could use the same strategy with jQuery. So JS that looked like:

    $('input[type=submit]:first').effect('pulsate', { times: 1 }, 1000);

Was turned into this:

1
2
3
4
5
   if($('body').hasClass('rsvps')) {
        if($('body').hasClass('update_notes'))
            $('input[type=submit]:first').effect('pulsate', { times: 1 }, 1000);
        ....
   }

Again, page scoped JavaScript that plays well in a single file. Moving forward I could use the same strategy with the JavaScript equivalent of SASS, CoffeScript, which was also brought into the Rails core with 3.1.

Was it worth it?

The upgrade to Rails 3.1.3 with full asset pipeline integration did take some time. An asset upgrade strategy needed to be figured out, changes needed to be made, and significant browser testing needed to be done. By the time I finished I was skeptical that the effort was worth it, but once I released to production I was pleasantly surprised to see that it was. Pages loaded significantly faster than they used to. I was using minification before the upgrade, but the Sprockets concatenation gave a big boost. I could actually feel the difference. Best of all I now have a nice stage set for building out mightyvites.com with heavy dependence on client-side processing.

Incoming search terms:

  • path to asset pipeline images
  • asset pipeline upgrade
  • ruby on rails asset pipeline
  • rails migrate to asset pipeline
  • rails pipeline ensure loaded only once
  • rails migrate asset pipeline
  • rails asset pipeline upgrade
  • rails3 qrcode
  • ruby asset pipeline sub web
  • ruby assets with hash names

Leave a Reply