Invoke Rails and Rake Faster!

A handy shell function for running rails and rake commands 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 can be 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|r|runner|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
}

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, runner, 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 further: 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

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 indispensable part of my Rails toolkit. Compared to straight up rails and rake, it’s fewer keystrokes, fewer mistakes, and a bit faster to boot.

Share this? Copy link

Feedback? Email me!

Hi! 👋 I’m Matt Brictson, a software engineer in San Francisco. This site is my excuse to practice UI design, fuss over CSS, and share my interest in open source. I blog about Rails, design patterns, and other development topics.

Recent articles

RSS
View all posts →

Open source projects

mattbrictson/rails-template

App template for Rails 7 projects; best practices for TDD, security, deployment, and developer productivity. Now with optional Vite integration! ⚡️

1,055
Updated 1 month ago

mattbrictson/tomo

A friendly CLI for deploying Rails apps ✨

360
Updated 20 days ago

More on GitHub →