Railsでマイグレーションを行った後に、ちょっとだけ修正を加えたいと思ってマイグレーションファイルを直接編集することがあるかもしれません。
そうしたときにマイグレーションファイルを直接変更した後でrails db:migrateをしても変更は反映されません。
ここでは、なぜマイグレーションファイルを直接変更したときに、マイグレーションが再度実行できないのか?どうすれば変更を反映できるのかについてまとめています。
なぜマイグレーションできないのか?(変更が反映されないのか?)
マイグレーションファイルを直接変更した場合にマイグレーションが実行されない理由は、マイグレーションの現在のバージョンとファイルが一致しているため、既にマイグレーション済みと判断されてしまうためです。
Railsの公式ガイドにも次のような記載があります。
いったんマイグレーションを実行してしまった後では、既存のマイグレーションを単に編集してもう一度マイグレーションをやり直しても意味がありません。Railsはマイグレーションが既に実行済みであると認識しているので、rails db:migrateを実行しても何も変更されません。
Active Record マイグレーション:https://railsguides.jp/active_record_migrations.html
マイグレーションとは何なのか?
そもそもですが、マイグレーションとは、データベースを直接操作することなく、データベースの構造(スキーマ)を変更する仕組みです。
簡単な流れでみると以下のようになります。
- 最初スキーマは空の状態です。
- マイグレーションファイルを作成して、マイグレーションを実行するとデータベースに指定したにスキーマが生成されます。
- このとき、バージョン管理ようのテーブルも自動生成され、その中でどのマイグレーションファイルまでを実行したかが記録されます。
- 新しいマイグレーションを実行する毎にバージョン追加されていきます。
このようにバージョン(履歴)管理をしているため、特定のマイグレーションを取り消して過去の状態に戻すこともできます。
対処法
対処は簡単です。ロールバックを使って、マイグレーションファイルの状態を実行前「down」の状態に戻してあげれば、再度rails db:migrate
でマイグレーションを実行できるようになります。
こういったときは、マイグレーションのバージョンを戻せば再度実行できます。ここでその方法について解説しています。
なお対処法は1つではなくいくつかあります。
rails db:rollbackでロールバックを実行する
ロールバックはrails db:rollback
で実行できます。
rails db:rollback
は直近の実行済みのマイグレーションファイルの内容を一つだけ見実行に戻します。
rails db:migrate
と合わせて実行すれば、マイグレーションが実行できます。
$rails db:rollback
$rails db:migrate
なお、$rails db:rollback STEP=数値
にすると指定した数の分だけマイグレーションファイルが前の状態に戻ります。
rails db:migrate:redoを使う
2つ目の対処法はRailsにはロールバックとマイグレーションを同時に実行できるrails db:migrate:redo
コマンドを使うことです。
$rails db:migrate:redo
これは以下のコマンドと同じです。
$rails db:rollback
$rails db:migrate
rails db:resetを使う
データベースのスキーマを完全にリセット(空っぽにする)する。rails db:reset
を使う方法もあります。
rails db:reset
を実行しても、マイグレーションファイルは残るので、再度マイグレーションすれば、新しいファイルの内容でスキーマができあがります。
ただし、データがなくなるので非推奨です。逆に、データも全部リセットして作り直したいという場合はこれを使うべきです。
$rails db:reset
$rails db:migrate
なお、db:resetコマンドは、db:dropでDBを削除して、db:setupで再設定しているのと同じ処理になります。
新しいマイグレーションファイルを作成する
既存のファイルを編集するのではなく、おとなしく、変更を加えた新しいマイグレーションファイルを作成するのも効果的な対処法です。
とくに、他の人たちと共同開発しているプロジェクトの場合は、マイグレーションファイルを直接書き変えると、他の人が持っている中身と合わなくなり、コンフリクトが発生するといった弊害があるので、修正を加えたマイグレーションファイルを新たに作成するのが一般的です。
手順は以下のようになります。
マイグレーションファイルを新規作成する
まずはマイグレーションファイルを新規作成します。
$ rails g migration マイグレーションクラス名
次の処理で、元ファイルをコピペするのでカラムや型は特に指定する必要はありません。
もし、指定したい場合は以下のように引数を与えます。
$ rails g migration マイグレーションクラス名 カラム名:型,,,
マイグレーションファイルを編集する
生成したマイグレーションファイルに以前のスキーマをコピペして、編集します。
マイグレーションを実行する
新たに作成したマイグレーションファイルの内容をデータベースに反映させるため、マイグレーションを実行します。
$ rails db:migrate
以上で変更内容の反映が完了します。
(補足)マイグレーションバージョンや履歴の確認方法
マイグレーション履歴の確認方法
マイグレーション履歴を確認するにはrake db:migrate:status
を実行します。
上が古く、下が新しいものです。
# rake db:migrate:status
database: rails_screamer_development
Status Migration ID Migration Name
--------------------------------------------------
up 20110521181506 Create pages
up 20110521182915 Create categories
up 20110703120321 Add position to pages
up 20110716180121 Add position to categories
down 20110724110158 Add english name to categorydevise
なお、一番左端の「up」はマイグレーション済み(DBに適用済み)、「down」はマイグレーション見実行(DB適用前)という状態を表しています。
$rails db:rollback
を実行すると直近の「up」が「down」になります。
現在の最新のマイグレーションバージョンの確認
現在の最新のマイグレーションバージョンの確認するには、rails db:version
を実行します。
# rails db:version
Current version: 20110716180121