【Rails】migrationのchangeとup/downって何が違うの?

Railsでmigrationを作成する時、changeメソッドだけが定義されていたり、upとdownメソッドの2つが定義されている時があります。

class AddColumnHoge < ActiveRecord::Migration 
  def change
  end
end
class ChangeColumnHoge < ActiveRecord::Migration 
  def up
  end

  def down
  end
end

こんな風に、migrationファイルを作成した時の名前で、生成されるclassのひな形が違います。

up/downについて

upとdownメソッドは、migrateを実行した時の処理と、rollbackした時の処理を定義します。

upで変更したものは、downで元に戻るようにしておかないと、正しくrollbackできません。

class ChangeColumnHoge < ActiveRecord::Migration 
  def up
    add_column :hoge, :fuga, :string
  end

  def down
    remove_column :hoge, :fuga
  end
end 

migrateを実行するとfugaカラムが追加され、rollbackするとfugaカラムが削除されます。

changeについて

changeメソッドは、migrateを実行した時の処理を定義します。

up/downと違うところは、rollback時の処理を勝手に反転して実行してくれるところです。
ですので、changeメソッドはrollback時の処理を書く必要はありません。

class AddColumnHoge < ActiveRecord::Migration 
  def change
    add_column :hoge, :fuga, :string
  end
end

これだけで、先ほどのup/downで挙げた例と同じ挙動になります。

rollback時はadd_columnを反転させて勝手にremove_columnが実行されます。

じゃあ全部changeでいいじゃん

と思いきや、changeだけでは成り立たないケースもあります。

class removeColumnHoge < ActiveRecord::Migration
  def change
    remove_column :hoge, :fuga
  end
end

これは、migrate実行時はカラムを削除するだけなので、問題なく実行できます。

しかし、rollback実行時は失敗します。
rollback時、fugaカラムの情報はどこにも書いていないからです。
型が文字列なのか数値なのかもわからないので、カラムを作成することが出来ません。

なので、こういうケースはup/downを使います。

class removeColumnHoge < ActiveRecord::Migration
  def up
    remove_column :hoge, :fuga
  end

  def down
    add_column :hoge, :fuga, :string
  end
end

downにfugaの定義をしっかりとしてあげることで、rollbackも正しく実行できます。

さらに上をいくRailsのよしなに力

つまり、migrationを生成する時の名前を見て、

  • 「remove***」だったら多分反転できないからup/downケースにしとくねー
  • 「add***」だったら消すだけだからchangeに任せてよ!

みたいなことをRailsがよしなにしてくれていたから、 名前によって生成されるClassのひな形が違うんですね。