zerowidth positive lookahead

Standalone script/runner bin scripts in Rails

script/runner or script/rails runner scripts are common in Rails apps for doing maintenance tasks. However, this only works well until you have several arguments to parse from the command line. Putting standalone scripts in /bin instead gives you easier, more flexible argument parsing and cleaner command lines and crontab entries.

Arguments with script/runner

First, you could just hack the argument parsing out, especially when using an argument delimiter like --:

$ script/rails runner lib/my_script.rb -e production -- arg1 arg2 arg3 --opt1=foo --opt2=bar

Not attractive, but here’s how:

#!/usr/bin/env ruby

# first try and show proper usage if arguments aren't well-formed:
def usage
  abort "usage: script/rails runner -e production scripts/#{__FILE__} -- [options]"

# not using script/rails runner?
usage unless Object.const_defined?(:Rails)

# missing the argument delimiter?
usage unless ARGV.include?("--")

# now, clean up ARGV:
loop { break if ARGV.shift == "--" }

# your code here, with a clean ARGV

Standalone bin script

All script/rails runner does is parse the optional environment out of the command line, bootstrap the Rails code, and then execute your code. If you assume RAILS_ENV is set appropriately in your production crontabs, then it’s easy to do this yourself.

The ideal command line:

$ bin/my_script arg1 arg2 arg3 --opt1=foo --opt2=bar

Rails 3

#!/usr/bin/env ruby

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require APP_PATH
# set Rails.env here if desired

# your code here...

Rails 2

#!/usr/bin/env ruby

require File.expand_path('../../config/boot',  __FILE__)
# set RAILS_ENV here if desired
require RAILS_ROOT + '/config/environment'

# your code here...

Option Parsing

Using the standard boilerplate normally provided by script/rails runner, this gives you a cleaner command line and more flexibility with option parsing. When using optparse, trollop or other option parsing libraries, you could still retain the -e <environment> option. Otherwise, just set RAILS_ENV appropriately and you’re good to go.