Rescuing migrations

DHH will probably hate my example, but…

AWDR talks about the difficulties and dangers of using complex
migrations–complex being defined as “doing more than one thing”. Not
being satisfied with the alternatives, I have come up with a system,
which people might want to consider for best practice. Example:

class CreateUsers < ActiveRecord::Migration
def self.up

create_table :users do |t|
  t.column :username,  :string,   :null => false
  t.column :salt,      :string
  t.column :pw,        :string,   :null => false
  t.column :expires,   :datetime, :null => false
  t.column :perm0,     :int,      :default => 0,  :null => false
end

begin
  add_index(:users, :username, :unique => true)
  User.send(:reset_root, 'Hownowbrowncow')
rescue Exception => e
  down rescue STDERR.puts "Nested exception executing

CreateUsers.down:\n#{$!}"
raise e
end
end

def self.down
drop_table :users
end
end

===

What we need to do is to ensure that any schema changes which are
completed before the migration ends are unwound if a fail occurs later
in the migration. In this simple example, we have one independent
schema change (create_table) followed by a pair of actions which may
or may not succeed. We contain these later actions in a block with a
rescue clause which unwinds the earlier schema changes. We use a
rescue clause on the unwinding action because it is the first error
which must be addressed–later errors are expected to be less
interesting.

If we had instead created two tables first, then we would nest blocks,
and drop only the first table if an exception occurs before the second
is created.

Comments?