55 Minutes

Welcome to the 55 Minutes blog.
55 Minutes is a web development consultancy in San Francisco building apps for design-led businesses and startups. On this blog we discuss the technology tools of our trade: Ruby on Rails, Django, Sass, OS X, and more.

Invoke Rails and Rake Faster! And With Fewer Mistakes

As a Ruby on Rails beginner I would always confuse the rails and rake commands. Database migration? rake. Database console? rails. It seemed arbitrary. Later I learned the differences, but still I found myself making fat-finger mistakes between the two. And on top of that, rails and rake are dog slow, meaning every mistake can come with a few-second penalty. Finally I got fed up and scripted the following solution in bash.

.bashrc

# Shortcut for `bundle exec rails` and `bundle exec rake`.
# If bin/rails and bin/rake are available, use them instead as they are much
# faster to execute than `bundle exec`.
function r() {
  if [[ "g|generate|c|console|s|server|db|dbconsole|new" =~ $1 ]]; then
    if [ -x bin/rails ]; then
      bin/rails "$@"
    elif [ -x script/rails ]; then
      script/rails "$@"
    else
      rails "$@"
    fi
  else
    if [ -x bin/rake ]; then
      bin/rake "$@"
    elif [ -x script/rake ]; then
      script/rake "$@"
    else
      rake "$@"
    fi
  fi
}
.bashrc – View Gist

What I’ve done in my .bashrc (see my dotfiles) is defined a shell command r that invokes rails or rake depending on the arguments given. If your argument to r is generate, console, server, dbconsole, new, or the one-letter aliases for those, the r command assumes you meant to invoke rails, and does so. Otherwise it assumes you meant rake.

For example:

r db:migrate
==  migrating....
r db
Welcome to psql 8.3.17, the PostgreSQL interactive terminal.
r s
=> Booting WEBrick

Short and sweet. No more fat-finger mistakes.

script/rails or bundle exec rails?

You’ll notice that r also favors script/rails over bundle exec rails. You may wonder why; after all we’ve been taught to always use bundle exec to ensure correct behavior of executables in a Rails project. But this is actually overkill for the rails command.

As it turns out, bundle exec rails simply invokes script/rails, which in turn initializes Bundler anyway. So bundle exec rails therefore runs Bundler’s setup twice, and for no good reason. (Actually, Bundler.setup is invoked three times!)

In fact, in my testing script/rails is up to 1 second faster than bundle exec rails. The upshot is that the r command should prefer to use script/rails if possible.

June 10, 2013 update: Rails 4 muddies the waters even futher: the rails executable is now in bin/rails. The good news is that r will do the right thing, first trying bin/rails (Rails 4 convention) and then script/rails (Rails 3 convention).

script/rake

A script/rake file is not included in standard Rails 3 projects, but you can use the same trick to get a 1-second boost over bundle exec rake. This may qualify as a hack, so proceed with caution.

#!/usr/bin/env ruby

# script/rake
# Run rake after loading Rails/Bundler; faster than `bundle exec rake`

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require 'rake'

Rake.application.run
rake.rb – View Gist

And don’t forget:

chmod a+x script/rake

June 10, 2013 update: Rails 4 includes a very similar rake script. It is in bin/rake for new Rails 4 projects.

Wrapping up

Pretty straightforward, right? I find that this simple r command is now an indenspensible part of my Rails toolkit. Compared to straight up rails and rake, it’s fewer keystrokes, fewer mistakes, and a bit faster to boot.

Suggestions? Discuss the Gist on GitHub.

comments powered by Disqus