Rails で元に戻せないマイグレーションを書くときの作法: ActiveRecord::IrreversibleMigration

ActiveRecordマイグレーションは,その中に up メソッドと down メソッドを書くことにより,データベースのスキーマを更新したり,変更を元に戻したりすることができ便利です.Rails 3.1 からは up, downchange メソッドにまとめて書くことができるようになりました.

しかし,すべてが元に戻せるマイグレーションかというと,そうではないことがあります.たとえば,

この図のように,integer だった vendor_code カラムを string に変更する場合,変更後のカラムに文字列を入れてしまうとマイグレーションで元に戻すことができません.文字列を数値に変換することができず,データが失われてしまうからです.このように,元に戻らないマイグレーションを書くときには,down メソッドで ActiveRecord::IrreversibleMigrationraise するようにします.

すなわち,マイグレーションは,

class ChangeVendorCodeToString < ActiveRecord::Migration
  def up
    change_column :items, :vendor_code, :string, null: false
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end

のようになります.こうしておくと,不用意な rollback でデータが破壊されるという悲劇がなくなります↓

% rake db:migrate
==  ChangeVendorCodeToString: migrating =======================================
-- change_column(:items, :vendor_code, :string, {:null=>false})
   -> 0.0295s
==  ChangeVendorCodeToString: migrated (0.0296s) ==============================
% rake db:rollback
==  ChangeVendorCodeToString: reverting =======================================
rake aborted!
An error has occurred, this and all later migrations canceled:

 ActiveRecord::IrreversibleMigration

 Tasks: TOP => db:rollback
 (See full trace by running task with --trace)

この記事を書いたときの Rails のバージョン

3.1.1