Understanding the Rails Asset Pipeline

Wednesday, January 3 2012 rails

Rails 3.1 marks a strange turning point in the evolution of Rails: many hard-core fans are feeling the framework is losing its edge and becoming over-engineered. That might be a premature opinion.

Is There a Problem?

It's a popular theme of late: "I liked Rails 2 much better":

Screen Shot 2012 01 12 at 9 17 27 AMScreen Shot 2012 01 12 at 9 18 17 AM That's Jeremy Ashkenas, creator of CoffeeScript and BackboneJS with a very blunt opinion about how Rails has changed over the years.
Despite how you feel about Rails (I happen to love it and run a business on it) - it's a valid question:

Is Rails 3 any better that Rails 2? Or is it worse?


Derick Bailey over at Los Techies

had an interesting post where he looked at how Rails has progressed over the years. It's a fun read, but he didn't have too many good things to say about Rails 3:

I have yet to hear WOW! that was SO EASY! out of anyone, regarding Rails 3.1 and the Asset Pipeline. Instead, I continue to hear more and more complaints about how difficult it is to make it work; how much work it takes to get it running, and how people are frustrated by Rails I hope they fix whatever the problem is, soon, and get Rails back on its rails. Its sad to see things in this state.

I remember reading that at the very time I decided to look into a possible upgrade for Tekpub. We were running smooth and happy on Rails 3.0.x - but 3.1 had some interesting improvements.
So I loaded up a new 3.1 project and moved everything over, and
gasped at how completely unusable it was. In short: the site took over 10 seconds to load and every time I ran any test (using RSpec)
I began to think that the Rails guys had literally lost their fucking minds .

Rails Fault?

Of course not. This is what happens when you move your focus a bit from "The Experience" to "The Engineering". It's a subtle shift - but it happens over the lifetime of any project. SubSonic did this: in the beginning it was all about the developer experience and the joy of having (basically) instant data access and over time we focused more and more on the engineering of it all.
When you do that, when you focus on the nuts and bolts rather than the shiny exterior, you (by default) as the user to get on board a bit and RTFM more. The Asset Pipeline is the perfect example of this.
So what is it and why is it there?

You Don't Have To Use It

EDIT:* It was suggested that I move this to the top of the post, and I agree. When Rails 3.1 was initially released it was much slower to load then it is currently. Recent releases have fixed this. In addition, you probably want to move into the pipeline slowly if you're upgrading. Before I get to any of this: you don't need to put your JS files inside your app/assets directory. If you have a big file (like jquerytools for instance) you can put it in the vendor/assets directory and it will be included in the page just as it's always been:
[cc lang='rails' ] = javascript
includetag "jquerytools" [/cc] The Asset Pipeline will do a search on disk before it processes anything - and if it finds a match, it will serve that file. The same goes for any ad-hoc CSS or JS you've written that you don't want to rewrite. Just pop that into public/assets and, like jquery_tools above, it will be pulled from the disk.
This is a nice way to slowly upgrade your site to using the Asset Pipeline if you're upgrading from 2.x. Or don't use it at all - there are still good reasons to upgrade - which I'll cover in later posts.

The Asset Pipeline

In short:
web developers tend to suck at writing concise, clean javascript and CSS . I know I do. The load times of our pages can make our sites look horrendously slow - and if you take time to examine the CSS and JS code it's almost always unminified and uncompressed, spread out over multiple pages with no caching directives. The Rails guys decided to fix this - WHILE AT THE SAME TIME making it easier and more fun for you to do "The Right Thing". Sometimes we don't want to do the right thing. Sometimes we need to be pulled by the shorties into the modern day. Rails excels at this - so

perhaps we should expect a little pain as we learn something new . That's what the Asset Pipeline is all about: compiling, compressing, minifying, and fingerprinting your CSS and Javascript while at the same time making it more fun.
Let's see how.

SASS and Your Design Model

There are all kinds of ways to put code behind CSS generation, perhaps the most favored of these is one of the first: SASS. The purpose of SASS is really quite simple: it helps you write less CSS while also being more effective.
For instance, I can create variables to use around my CSS:
[cc lang='rails' ] $gray: #ccc; $darker: #333; $lighter: #e5e5e5; $column: 42px;


width:(5 * $column); //this results in 5 * 48px, 240px
color: $darker;
} [/cc] That's the idea - the things with the "$" are variables and they can be sizes or colors, whatever. You can then use some logic in your CSS to structure things happily. Seems a bit wonky, I know, but stay with me.
You can embed one document in another by using "@import". This is handy if you want to have a set of global variables and site-wide settings that are easily tweaked.

If you think of CSS as a bit of a ... "Design Model" - it starts to become clear.

Check out the

Frameless CSS "framework". It's not so much a framework as a bit of "a good way of doing it" - here's

their SASS main sheet. You can see that it's a bunch of variables and media queries that go into Responsive Design (something I'll blog about later).
It's nice, but we can structure this to make more sense.

CSS Structure and The Rails Pipeline

*Every site had the same CSS approach:

*Structural settings

*Typographical settings

*Stylistic settings

*A Reset sheet

*And if you're into forward-thinking CSS, a set of media queries for Responsive Design Organizing this much CSS can be a complete nightmare! That's why we have The Asset Pipeline. Not only does it help you arrange your CSS in a much nicer way, it also helps you deliver and work with that CSS with little effort.
How? Let's organize our stylesheets so they make more sense. I'll create a set of 6:






*typography.css.scss In "globals.css.scss" I'll put the site-wide settings that all the other sheets will use. This won't output anything - it will only provide variable declarations:

The "$cols" stuff you see here is the Frameless stuff - I have it go all the way up to $cols20.
Now, I need to include that in every other sheet - and SASS makes this simple. Let's take a look at "structure.css.scss":

Again: SASS isn't anything supernatural. It's just CSS with some love. At the very top there I have an @import directive, which acts like a #INCLUDE statement if you will, and drops all of the variables I need into structure.css.scss so I can use them in that sheet. I do the same for all the other sheets I'm using (typography, styles, etc).
At this point I'll sum up the overall approach by saying that you divide out your "Design Model" by purpose so you know where to go when you need to fix things. Some ugly type? Fix it in typography.css.scss. Something not aligned, it's probably in structure.css.scss.
What does this have to do with Rails and the Asset Pipeline?
A lot of people think this stuff is served on the fly - and indeed it can be, but that's not a very good idea. When you're developing it makes perfect sense - however when you're in production you don't want your users to wait for this stuff to get processes along with your pages.
So the Asset Pipeline does that for you: it compiles the SASS and CoffeeScript files per request in development mode (plus a few other things), and it compiles/minifies/uglifies/compresses the same files in production.
This is extremely important - that's a lot of work and Rails is just doing it for you!

Asset Pipeline In Production

All you need to do to use the asset pipeline is invoke it in your layout:
[cc lang='rails' ] = stylesheetlinktag "application" = javascriptincludetag "application" [/cc] These invocations fire up the pipeline and on first request, will compress/minify/concatenate every SCSS file into a single file called "global" with a fingerprinted timestamp as part of the filename, not the querystring (which some browsers will simply ignore.
You want your users to have only one CSS file to download and you want their browser to cache your CSS so it doesn't need to be loadedagain. All of this will make your site faster to load, which makes your user very happy.
All of this applies to CoffeeScript as well. You can work on your CoffeeScript files inside the assets directory and it will be compiled/uglified/minified/concatenated in the exact same way as the SASS stuff. If you like CoffeeScript - then this is a great thing.
If you don't care, that's OK to.

Some Tips

Much of the angst that comes from Rails 3.1 is the load time. This is due, primarily, to the Asset Pipeline trying to do too much. If you load up all of your JS files and CSS files, as well as all of your images into app/assets, you're in for a world of hurt.
Only put in there what needs to be processed. I don't have a single image in my Tekpub upgrade app here, and it loads up just fine - in fact a bit faster than it's 3.0.x brother.
Make sure you

RTFM and know what's going on before you expect Rails to simply do everything for you. We're sort of past that point in Rails history. The neat thing is that, with a little understanding and some knowledge - doing the right thing is drop-dead easy.