はじめに
ActiveRecordの機能のひとつ、マイグレーションは便利な機能ですが、使い方を間違えるとせっかく作ったデータベースを破壊してしまいかねません。データベースの操作を間違えたときに有用なロールバックも、きちんと手順を守って行わないとマイグレーションの整合性が崩れてしまう可能性があります。
本記事では、マイグレーションの実行についてまとめています。
なお、マイグレーションの作成・編集については以下の記事でまとめていますので、併せてご覧いただければと思います。
マイグレーションの実行
ステータスコマンド
現在のマイグレーションがどこまで実行されているかなどをコマンドで確認することができます。特にチーム開発を行っているときやロールバックを行う前には必ず実行することをおすすめします。
$ rails db:migrate:status
database: db/development.sqlite3
Status Migration ID Migration Name
--------------------------------------------------
up 20190808140406 Create articles
up 20190810152518 Add category to articles
up 20190812090038 Add picture to articles
Statusがup
ならマイグレーションが実行されている、down
ならされていないという意味になります。Migration IDは、後述する特定のマイグレーションの実行などで必要となるバージョンです。
マイグレートコマンド
作成したマイグレーションを実行しデータベースの操作を行うコマンドです。最もよく使うコマンドだと思います。
$ rails db:migrate
特定のマイグレーションまで実行したい場合、マイグレーションのバージョンを指定することもできます。
$ rails db:migrate VERSION=20190812090038
このコマンドを実行すると、指定したバージョンを含むそれまでのマイグレーションがすべて実行されます。指定したバージョンが先の場合すべてのバージョンをup
にし、前の場合すべてのバージョンをdown
にします。
特定のマイグレーションだけをup
またはdown
にすることもできます。
$ rails db:migrate:up VERSION=20190812090038
$ rails db:migrate:down VERSION=20190812090038
ロールバックコマンド
一度行ったマイグレーションを取り消したい場合、ロールバックコマンドを実行します。以下のコマンドは直近のマイグレーションだけを取り消します。
$ rails db:rollback
いくつかのマイグレーションを一気に取り消す場合、取り消すマイグレーション数を指定することもできます。
$ rails db:rollback STEP=5
このコマンドは直近から5世代前までのマイグレーションがすべて取り消されます。
トラブルシューティング
マイグレーションについてきちんと理解していないうちは、マイグレーションの実行周りでトラブルが起こりがちです。大抵は無理解からくる自分のミスが原因なわけですが、トラブルが起こったときは混乱して右往左往してしまいます。
マイグレーションを実行する際によく起こるであろうトラブルとそのベストプラクティスについてまとめてみました。
マイグレーションを修正したい場合
例えば、マイグレーションファイル作成時にカラム名を間違って記述してしまい、気付かないままマイグレーションを実行してしまった場合。最も簡単な方法は、ロールバックコマンドを実行してマイグレーションを取り消し、マイグレーションファイルを正しく修正してからもう一度マイグレーションを実行することです。
# マイグレートを取り消し
$ rails db:rollback
# マイグレーションファイルを修正
$ vi db/migrate/20190812090038_add_picture_to_articles.rb
# 再度、マイグレートを実行
$ rails db:migrate
では、間違ったマイグレーションが直近ではなくもっと前の世代だった場合はどうでしょうか。現在のマイグレーションと間違ったマイグレーションの間に正しいマイグレーションがいくつも存在している状態です。
この場合は、ステータスコマンドで間違ったマイグレーションまでの世代数を確認し、ロールバックコマンドでその世代までのマイグレーションをすべて取り消します。あとはマイグレーションファイルを正しく修正してからもう一度マイグレーションを実行します。
# ステータスを確認
$ rails db:migrate:status
# 世代を指定してマイグレートを取り消し
$ rails db:rollback STEP=5
# マイグレーションファイルを修正
$ vi db/migrate/20190812090038_add_picture_to_articles.rb
# 再度、マイグレートを実行
$ rails db:migrate
あるいは、間違いを修正するためのマイグレーションファイルを新たに作成するという方法もあります。カラム名の間違いくらいだったら、rename_column
を使って簡単に修正することができます。
# マイグレーションファイルを作成
$ rails generate migration RenameColumnFromArticles
# 作成したマイグレーションファイルを編集
$ vi db/migrate/20190814110732_rename_column_from_articles.rb
# マイグレーションを実行
$ rails:migrate
カラム名を修正するマイグレーションファイル。
class RenameColumnFromArticles < ActiveRecord::Migration
def change
rename_column :articles, :content, :body
end
end
この方法ならロールバックする必要はありません。常に前進し続けるというスタイルです。デメリットとしては、ロールバックする場合と比べてマイグレーションの数が肥大化しがちだということです。その結果、デプロイ時などにマイグレーションが一気に実行されると時間がかかりすぎることに繋がります。
マイグレーションを削除したい場合
例えば、追加したカラムが不要になったので削除したい場合。通常であれば、カラムを削除するマイグレーションファイルを作成してマイグレーションを実行するという方法で十分でしょう。
# マイグレーションファイルを作成
$ rails generate migration RemoveCategoryFromArticles category:string
# マイグレートを実行
$ rails db:migrate
カラムを削除するマイグレーションファイル。
class RemoveCategoryFromArticles < ActiveRecord::Migration
def change
remove_column :articles, :category
end
end
しかし、何らかの理由によりカラムを追加するマイグレーションごと削除してしまいたい場合はどうすればいいでしょうか。あまりないことではありますが、できないわけではありません。
まず、ステータスコマンドで削除したいマイグレーションのバージョンを確認します。そして、対象のマイグレーションだけを取り消し、最後にマイグレーションファイルを手動で削除します。
# ステータスを確認
$ rails db:migrate:status
# 対象のマイグレーションを取り消し
$ rails db:migrate:down VERSION=20190814110732
# マイグレーションファイルを削除
$ rm db/migrate/20190812090038_add_picture_to_articles.rb
取り消す前に削除してしまった場合
マイグレーションを取り消す前にマイグレーションファイルを削除してしまい、さらに復元することもできない場合。この状態でステータスを確認すると、以下のようになっているはずです。このような状態だと、マイグレーションファイルがないのでdown
にすることもできません。
$ rails db:migrate:status
database: db/development.sqlite3
Status Migration ID Migration Name
--------------------------------------------------
up 20190808140406 Create articles
up 20190810152518 Add category to articles
up 20190812090038 ********** NO FILE **********
こうなってしまったら、一度ダミーのマイグレーションファイルを作成し、それからマイグレーションを取り消し、マイグレーションファイルを手動で削除します。
# ダミーのマイグレーションファイルを作成
# (重要:タイムスタンプは必ず一致させる)
$ touch db/migrate/20190812090038_dummy.rb
# 適当なマイグレーションを記述する
$ vi /db/migrate/20190812090038_dummy.rb
# マイグレーションを実行
$ rails db:migrate
# 対象のマイグレーションを取り消し
$ rails db:migrate:down VERSION=20190812090038
# マイグレーションファイルを削除
$ rm db/migrate/20190812090038_dummy.rb
ダミーのマイグレーションファイル。
class Dummy < ActiveRecord::Migration
def change
end
end
もう一度ステータスを確認するとNO FILE
の表示が消えているはずです。
まとめ
トラブルシューティングのセクションでは、私が実際に陥ったトラブルについても書いています。当時はまだRuby on Railsを使い始めたばかりの頃だったので、ちんぷんかんぷんになってとにかく焦ったことを今でも覚えています。マイグレーションの実行周りはとにかくトラブルが起こりやすいので、慎重に行う必要がありますね。
本記事を参考にして、マイグレーションの実行について覚えていただければと思います。