The EdgeCase Library Need Development? Check us out!

Bootstrapping Rails

Posted 12 March 2012

Author Aaron Christy

Pretty & Shiny

There is an enormous amount of excitement surrounding Twitter's Bootstrap presentational framework and for good reason. Bootstrap makes it simple to create nice looking buttons, forms, typography, and overall site layout. It also solves many cross browser complexities. . . and let's face it, makes mediocre designers look like they know what they are doing.

Rails + Bootstrap ... Where's the Flexibility?

Recently, I had a Rails 3 project and wanted all the beauty of Bootstrap 2, but I had several specific needs that had to be met.

  • It must allow the flexibility to easily customize styles using built-in variables. (This means I could not simply download and include the pre-generated Bootstrap css files.)
  • It must fit into the Rails asset pipeline.
  • It must use native Bootstrap LESS CSS files. (Other parts of the site uses Sass, but I didn't want to rely on a Sass port of Bootstrap for fear of a third party repo becoming stale).
  • Any Boostrap customizations I implement must be compartmentalized and out of my way.

1. Modify Gemfile

Add less-rails-bootstrap to your gemfile and 'bundle' it up:

gem 'less-rails-bootstrap'

The less-rails-bootstrap gem:

  • works atop the less-rails gem and provides a simple way to inject Bootstrap source files into the Rails asset pipeline
  • includes the Bootstrap css and js files, so there is no need to download them separately
  • namespaces the Bootstrap css and js files and provides useful hooks to conditionally include and override them when necessary
  • mirrors the Bootstrap version as close as possible (so, gem version 2.0.6 will contain Bootstrap 2.0.1)

2. Create a Custom Loader File

In order to perform your own Bootstrap customizations, you will need to have full control over the Boostrap load order.

First, create a nice place to keep all your bootstrap customizations.

mkdir -p app/assets/stylesheets/bootstrap
touch app/assets/stylesheets/bootstrap/loader.css.less

You will now have this structure:

├── app
│   ├── assets
│   │   └── stylesheets
│   │       ├── bootstrap
│   │       │   └── loader.css.less

Modify your loader file: app/assets/stylesheets/bootstrap/loader.css.less

@import "twitter/bootstrap/reset";
@import "twitter/bootstrap/variables";
@import "bootstrap/_variables";
@import "twitter/bootstrap/mixins";
@import "twitter/bootstrap/scaffolding";
@import "twitter/bootstrap/grid";
@import "twitter/bootstrap/layouts";
@import "twitter/bootstrap/type";
@import "twitter/bootstrap/code";
@import "twitter/bootstrap/forms";
@import "twitter/bootstrap/tables";
@import "twitter/bootstrap/sprites";
@import "twitter/bootstrap/dropdowns";
@import "twitter/bootstrap/wells";
@import "twitter/bootstrap/component-animations";
@import "twitter/bootstrap/close";
@import "twitter/bootstrap/buttons";
@import "twitter/bootstrap/button-groups";
@import "twitter/bootstrap/alerts";
@import "twitter/bootstrap/navs";
@import "twitter/bootstrap/navbar";
@import "twitter/bootstrap/breadcrumbs";
@import "twitter/bootstrap/pagination";
@import "twitter/bootstrap/pager";
@import "twitter/bootstrap/modals";
@import "twitter/bootstrap/tooltip";
@import "twitter/bootstrap/popovers";
@import "twitter/bootstrap/thumbnails";
@import "twitter/bootstrap/labels";
@import "twitter/bootstrap/progress-bars";
@import "twitter/bootstrap/accordion";
@import "twitter/bootstrap/carousel";
@import "twitter/bootstrap/hero-unit";
@import "twitter/bootstrap/utilities";

3. Mix It Up

Let's say you want all the tables in your layout to be bordered and alternate rows striped. You could add the Bootstrap .table, .table-bordered, and .table-striped css classes to every table in your app, but don't be ridiculous, there is a better way ... mixins!

First, organize yourself. Create a tables.css.less file:

touch app/assets/stylesheets/bootstrap/tables.css.less

Edit your app/assets/stylesheets/bootstrap/tables.css.less file like so:

@import "twitter/bootstrap/variables";
@import "twitter/bootstrap/mixins";
@import "twitter/bootstrap/tables";

table {
  .table;
  .table-bordered;
  .table-striped;
}

BOOM! You have forced every table tag to have default classes without changing any of your markup. Just be sure you @import any bootstrap modules that you will be overriding. Since this is a mixin, I had to include the @import "twitter/bootstrap/mixins".

4. Rinse & Repeat

As a convention, I created a separate file named after each major Bootstrap module for anything I want to override.

So in my project, I have all my customizations neatly organized and self-contained:

├── app
│   ├── assets
│   │   └── stylesheets
│   │       ├── bootstrap
│   │       │   └── ...
│   │       │   └── tables.css.less
│   │       │   └── forms.css.less
│   │       │   └── typography.css.less

5. Add Custom Variables

Twitter Bootstrap comes with global custom LESS variables that can be modified in one place and applied everywhere.

Let's get organized and then change the form buttons to be green instead of the default blue.

touch app/assets/stylesheets/bootstrap/_variables.less

Now your structure looks like so:

├── app
│   ├── assets
│   │   └── stylesheets
│   │       ├── bootstrap
│   │       │   ├── _variables.less
│   │       │   └── tables.css.less

Use the app/assets/stylesheets/bootstrap/_variables.less file to store all your variables:

@import "twitter/bootstrap/variables";
@primaryButtonBackground: #46a546;

You can find the full list of Bootstrap variables here that can be overriden.

6. Add Bootstrap into the Asset Pipeline

Finally, modify your base application stylesheet: app/assets/stylesheets/application.css

/*
 *= require 'bootstrap/loader'
 *= require_self
 *= require_tree .
*/

ZIPPY-ZOW! That's all there is to it. . . happy bootstrapping!