15

I'm new to Rails, and having trouble figuring out the best way to organize my assets. The purpose of this question is to collect my thoughts, solicit input, and evolve the document over time - perhaps it can be a Rails Guide someday. (The Rails Wiki appears to be dead.) This will be meant as an aid to conceptualization for novices, not a reference, so it will be limited to the most common scenarios.


Asset Pipeline - Overview

For details on the purpose, benefits, and inner workings of the pipeline, start with this guide: http://guides.rubyonrails.org/asset_pipeline.html I will only summarize the bits relevant to my purposes here.

The reasons the pipeline is necessary are:

  1. Compilation: To compile high-level languages (ERb, Haml, Sass, LESS, CoffeeScript...) into plain CSS/JS.

The additional benefits of the pipeline are:

  1. Concatenation: Combining multiple files into one to improve client performance.
  2. Minification: Removing whitespace and other clever optimizations to reduce file size.
  3. Fingerprinting: Added an MD5 hash of the file contents to the filename to force caches to **fetch the file again when it changes.

Asset Pipeline - Default Filesystem Layout

  • app|lib|vender/assets/ - Intended for files which will be processed by the pipeline.
  • app/assets/ - Intended specifically for files you created for your application.
  • lib/assets/ - Intended specifically for files you created for sharing across multiple applications.
  • vendor/assets/ - Intended specifically for files created by others, such as jQuery and Twitter Bootstrap (though they are frequently provided by gems instead of being imported directly into /vender).
  • public/ - Files in here are left as is, and fetchable directly from the root path ('/') of your web app.

Asset Pipeline - Default Files and Behavior

app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require_tree .

app/assets/stylesheets/application.css

/*
 *= require_self
 *= require_tree .
 */

public/404.html
public/robots.txt
...

Gemfile

...
gem 'jquery-rails'
...

Here's what the asset pipeline compiler does using the default setup of a new Rails app:

  1. The compiler, by default, will process application.js, application.css, and all non-JS/CSS files (images, mostly).
  2. The two application files contain sprockets directives (the comment lines that start with =). Sprockets is the library that powers the Rails asset pipeline compilation. These directives are also called manifests, since they list files for inclusion.
  3. application.js contains a manifest that pulls in two jquery files (which exist in the jquery-rails gem, not in your app), then pulls in all files in the app/assets/javascripts/ tree via require_tree .. All files included via this manifest will get compiled into a single file called application-[the MD5 hash].js, and placed in public/assets/.
  4. application.css contains a manifest that pulls in all files in the app/assets/stylesheets/ tree via require_tree .. The required_self directive tells the compiler to include any CSS content in the application.css file itself, and in the order of the directives. So, in this case, the CSS in application.css will appear above the rest. All files included via this manifest will get compiled into a single file called application-[the MD5 hash].css, and placed in public/assets/.
  5. All non-JS/CSS files (images, mostly) in the app/assets tree will also get fingerprinted and placed in public/assets/, with the directory structure intact. For example, app/assets/images/categories/computers.png will end up as public/assets/categories/computers-[the MD5 hash].png.

Conceptualizing Intra-Asset Dependency Scenarios

Images

Images have no dependencies between them, they always stand alone.

Stylesheets

  • CSS: CSS files can import each other, which will work as long as paths are correct, though it's probably not the best technique.
  • Sass: Sass files can import each other, as well as share variables and mixins, but only when they are still Sass (not after compiling to CSS), and only via Sass imports. If you have sprockets directives in application.css.scss that requires 'a' and 'b', they will be compiled in separate contexts before merging. To share variables and mixins, you must import 'a' from 'b' or vice versa using Sass import directives. (See Key Concept 1 below.)
  • LESS: [Don't know enough about this.]

JavaScript

  • JS: JavaScript components have inter-dependencies (example: Twitter Bootstrap uses jQuery). However, they all get resolves at runtime in the browser, so it doesn't matter how your organize/combine the files in your project, as long as all the contents eventually get loaded by the browser.
  • CoffeeScript: [Don't know enough about this.]

Helper Behavior - Rails Views

TODO

Helper Behavior - Sass

TODO

Best Practices - Key Concepts

  1. The pipeline is for preparing assets for production. Think of it as part of the deployment system, not the application itself. Establish the logical structure of your app yourself, then configure sprockets to operate correctly on that structure.

Best Practices - The Common Asset Scenarios

TODO

Best Practices - Summary of Generally Useful Defaults

TODO

** Questions **

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
odigity
  • 7,568
  • 4
  • 37
  • 51
  • I'm constructing this doc as best and quickly as I can, but could really use some help ensuring it's correct, comprehensive, and well organized. Gimme some comment love. – odigity Jul 14 '12 at 13:51
  • There is already a Rails Guide on the asset pipeline - http://guides.rubyonrails.org/asset_pipeline.html If you think it needs more information, perhaps work on making that better instead. – sevenseacat Jul 14 '12 at 13:53
  • 1
    Ok, nearly everyone I'm shown this to has now either a) bitched about me not using StackOverflow for it's intended purpose or b) insisted that I work directly on the Asset Pipeline guide instead, even after I explained to them why that's not the right thing for me to do yet (which they never seem to understand). I'm pretty close to calling this whole thing off. – odigity Jul 14 '12 at 14:05
  • 2
    If you're going to do something like this, it should *at the very least* be made community wiki. Regardless, there is no question here. "Perhaps it can be a Rails guide someday"—the Rails guides are editable by the community, so feel free to improve that instead of making something new. – Andrew Marshall Jul 14 '12 at 17:05
  • I hadn't heard of Community Wiki. I looked it up, found a couple of pages about it. This one seems relevant - apparently it's being demphasized: http://blog.stackoverflow.com/2011/08/the-future-of-community-wiki/ It looks like the bottom line is this kind of content is not considered appropriate for SO. So I need to find another place for it (no, not the Rails Guides, I'm not ready for anything nearly that formal). – odigity Jul 14 '12 at 18:11
  • I would be very interested in this question being answered. – port5432 Feb 10 '14 at 13:21

0 Answers0