Working with Ruby
Occasional blog posts about Ruby updates, tools, editor tweaks, and random snippets. You might also be interested in my newer project that docuements lesser-known features in Ruby: Idiosyncratic Ruby.

Three little tips for slimmer Rails migrations

Rails migrations are easy to understand and easy to write. However, you can save some unnecessary key strokes by applying these three tips :)

Let’s take a simple example Rails 3.0/Rails 2.3 migration:

class AddWebsiteToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :website, :string
  end

  def self.down
    remove_column :users, :website
  end
end

Tip 1) No self. prefix

Until Rails 3.0, you have to define class methods of your newly created migration, so you need to prefix your up and down methods with self. You can get rid of this verboseness by upgrading to Rails 3.1 (which uses instance methods) or using the helper method from tip 2.

Tip 2) Kernel#migration helper method

I often use older migrations as a template for new ones. One annoying step about this approach is to modify the class name of the migration to match the file name (AddWebsiteToUsers in this case). This task can be automated to look like this:

migration do
  def up
    add_column :users, :website, :string
  end

  def down
    remove_column :users, :website
  end
end

This bearable amount of magic is done by this little snippet (which could also be written as an one-liner):

 1
2
3
4
5
6
7
8
9
def migration(&block)
  if caller[0].rindex(/(?:[0-9]+)_([_a-z0-9]*).rb:\d+(?::in `.*')?$/)
    m = Object.const_set $1.camelize, Class.new(ActiveRecord::Migration)
    m.instance_eval(&block) # Rails 3.0/2.3
    # m.class_eval(&block)  # Rails 3.1 or Rails 3.0/2.3 without tip 1 applied
  else
    raise ArgumentError, "Could not create migration at: #{caller[0]}"
  end
end

Just add it to a config/initializer/* file and you are ready to use the feature.

Alternatively, it’s available as Rails plugin/gem, which also modifies the migration generator to use the new syntax:

Plugin version

rails plugin install git://github.com/janlelis/slim_migrations.git -r 3.0

Gem version

gem 'slim_migrations', '~> 3.0.0'

The plugin is compatible with Rails 3.1, Rails 3.0 and Rails 2.3 (just checkout the proper branch/version). It also comes with a slim_migrations:update_syntax rake task for translating all of your current migrations.

Tip 3) Use Rails 3.1’s reversible migrations

As mentioned in tip 1, up and down are Migration instance methods in Rails 3.1. It also introduces a new change method that can be used as an up alternative. It is run normally when migrating up, but also provides the capability of rolling back your migration. Of course, it only works for easy migrations, but in many cases, you don’t want to do advanced stuff!

With all three tips applied to it, the example migration looks pretty sexy now:

migration do
  def change
    add_column :users, :website, :string
  end
end

For more information about Rails 3.1’s change method, see the blog post by Rohit Arondekar!

Creative Commons License