Railsのマイグレーションファイルでカラム追加ってどう書きましたっけ。
class AddHeightToHumans < ActiveRecord::Migration
def change
add_column :humans, :height, :integer
end
end
そうそう、こんなんでした。
では時が流れ、諸事情あってこのカラムは用済みですというお話になったとして、カラム削除はどう書きましょう?
class RemoveHeightToHumans < ActiveRecord::Migration
def change
remove_column :humans, :height
end
end
うろ覚えでWebのサンプル引っ張ってくるとこんな風に書くと思いますがちょっと待った。
カラム削除のマイグレーションをdb:rollbackしようとしてエラーが出たことありませんか?
こんな感じになると思います(実際のログをもとに改変,DBはpostgres)。
$ bundle exec rake db:migrate:rollback STEP=1
D, [2015-12-09T15:40:00.307159 #18054] DEBUG -- : ActiveRecord::SchemaMigration Load (25.9ms) SELECT "schema_migrations".* FROM "schema_migrations"
D, [2015-12-09T15:40:00.463394 #18054] DEBUG -- : ActiveRecord::SchemaMigration Load (0.6ms) SELECT "schema_migrations".* FROM "schema_migrations"
I, [2015-12-09T15:40:00.478230 #18054] INFO -- : Migrating to RemoveHeightToHumans (201512XXXXXXXX)
D, [2015-12-09T15:40:00.493499 #18054] DEBUG -- : (0.3ms) BEGIN
== 20151208031040 RemoveHeightToHumans: reverting ===============================
D, [2015-12-09T15:40:00.512146 #18054] DEBUG -- : (0.2ms) ROLLBACK
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
remove_column is only reversible if given a type.
remove_columnに型がないって怒られてしまいます。
逆に言えば型を書けばロールバックできるんですね。
上はログをまとめやすく、実際のプロジェクトの名称が出てこないように恣意的に取り出していますが、実際にはなんとなくエラーの文面を流していた人もいるのではないでしょうか(私の場合はreversibleのあたりで思考停止して「なんかダメっぽいぞ」と反射で対処してしまってました。脳筋…)
特に開発中にブランチによってカラムが違ったりしてマイグレーションで増減させるときにこの辺りで刺さるとつらいことになります。
きちんと型指定してあげればchangeメソッドをわざわざupとdownに書きなおして記述するパターンやremove_columnをコメントアウトしてロールバックしてから手でカラム追加とかいう邪法ともおさらばです。
メソッド定義も一応チェックしておきます。
remove_column(table_name, column_name, type = nil, options = {}) public
モロに引数にtypeってありますね。
で、辿り着いたのが型を指定したこちら。
ぶっちゃけ、rails g migration RemoveHeightToHumans height
ってやれば最初からこの形式で自動生成してくれますが、コマンドでのカラム指定忘れて手で書いちゃうとこれに辿りつけないことがあります。たぶん私だけじゃないはず。
class RemoveHeightToHumans < ActiveRecord::Migration
def change
remove_column :humans, :height, :integer
end
end
ちなみにremove_columnsは型指定できないのでこのやり方はできません。
コマンド叩いたらこんな感じです(実際の出力をもとに改変)。
$ bundle exec rake db:rollback
== 201512XXXXXXXX RemoveHeightToHumans: reverting ===============================
-- add_column(:humans, :height, :integer, {:default=>false})
-> 0.0813s
== 201512XXXXXXXX RemoveHeightToHumans: reverted (0.0815s) ======================
できた
remove_indexも同じ要領で、nameだけ書いても消せるけどrollbackの時に戻せなくなるので、関係するカラムを書いてあげましょう。
もっと言うならschema.rbのindex定義をコピペしてadd_indexをremove_indexに変えるだけでOK。
「基本すぎない?」と突っ込まれそうで怖いのですが、私の観測範囲での感触では削除時に型指定できてないマイグレーションファイルまだまだあるんじゃないかなあ、という認識です。
普段はあまり触らないために忘れがちになるところでもあり、なまじ型指定しなくても動いてしまうのですが、折を見て思い出してやってください。