またまたRails 3.1 ネタです。Rails 3.1 では migration ファイルのデフォルトフォーマットが変わりました。
rails g model blog title:string body:text
としたとき、Rails 3.0 では下記のファイルが生成されます
class CreateBlogs < ActiveRecord::Migration def self.up create_table :blogs do |t| t.string :title t.text :body t.timestamps end end def self.down drop_table :blogs end end
Rails 3.1 では下記のファイルが生成されます。
class CreateBlogs < ActiveRecord::Migration def change create_table :blogs do |t| t.string :title t.text :body t.timestamps end end end
だいぶすっきりしましたね。Rails 3.1 では、上記のように migration の up, down 両方を change メソッド中にまとめるようになりました。change メソッド中に定義された情報は、rollbackされたときに自動的に反転されます。例えば上記の例なら rollback 時には drop_table が実行されることになります。
ただ、なんでも change メソッドを使えばOKかというとそうではありません。例えば、下記のような migration ファイルを作り、rake db:rollback とするとエラー(ActiveRecord::IrreversibleMigration)となってしまいます。どうしてエラーになるのでしょうか?
class RemoveTitleFromBlog < ActiveRecord::Migration def change remove_column :blogs, :title end end
rake db:rollback した場合は、普通に考えれば remove_column の逆のメソッドである add_column が実行されるはずですが、上記の記述では追加するカラムの型の情報が足りず、add_column することができません。このような場合は、従来通りの up メソッドや down メソッドを定義してあげる必要があります。ただ、up メソッドや down メソッドは Rails 3.0 までとは違いインスタンスメソッドとして定義してあげなければなりません。
class RemoveTitleFromBlog < ActiveRecord::Migration def up remove_column :blogs, :title end def down add_column :blogs, :title, :string end end
個人的には down 中の定義をtypoして、たまにrollbackした際に時間をロスすることがあるので、この仕様変更はありがたいです。RailsのDRY具合もだいぶ極まってきた感じがしますね。