【初心者向け】ブランチを切り替えてもなぜマイグレーションがスキーマに反映されてしまうのか
はじめに
Ruby on Railsをgit管理をしながら開発しています。
ブランチAでマイグレーションrails db:migrate
を実行した後に、ブランチBに切り替えてrails db:migrate
をするとマイグレーションファイルにはないはずのschema.rb
にはブランチAのマイグレーション差分が発生してしまいます。
そのため、ブランチAで実行したマイグレーションはrails db:rollback
してからブランチBに変更するか、大規模なロールバックの場合はrails db:reset
をするかどちらかの対応になるかと思います。
ただ、よくよく考えてみるとマイグレーションファイルからスキーマファイルを生成している、だけの知識では何故こうなるのかの説明がつかないです。
今回はマイグレーションファイルは存在しないはずなのになぜそのようなことになるのか、推測含めまとめました。
マイグレーションファイルでスキーマファイルは管理されているのか?
Railsマイグレーションのドキュメントを読んでみます。
スキーマファイルの意味について
Railsのマイグレーションは強力ではありますが、データベースのスキーマを作成するための信頼できる情報源ではありません。信頼できる情報源は、やはりデータベースです。Railsは、デフォルトでdb/schema.rbファイルを生成してデータベーススキーマの最新の状態のキャプチャを試みます。
db/schema.rbやdb/structure.sqlは、使っているデータベースの最新ステートのスナップショットであり、そのデータベースを再構築するための情報源として信頼できます。
マイグレーションファイルからのみでスキーマファイルを作成しているかと思いきや、ここを見るとどうやらそれだけではなさそうです。
実際にはデータベースのデータから差分を見ていることがわかります。
ではデータベースのどこで管理しているか?
db/migrate/ディレクトリ内のマイグレーションファイルを削除しても、マイグレーションファイルが存在していたときにrails db:migrateが実行されたあらゆる環境は、Rails内部のschema_migrationsという名前のデータベース内に保存されている(マイグレーションファイル固有の)マイグレーションタイムスタンプへの参照を保持し続けます。このテーブルは、特定の環境でマイグレーションが実行されたことがあるかどうかをトラッキングするのに用いられます。
データベース内のテーブルを見てみましょう。おそらくschema_migrations
というテーブルが存在していると思います。
schema_migrations
で一度実行されたマイグレーションファイルのタイムスタンプを保存しています。
rails db:migrate
されたタイミングでこのテーブルを確認しており、存在しないマイグレーションファイルに関してはデータベースからスキーマファイルを生成、みたいなことがされてると推測されます(githubみましたが推測の域を出ませんでした。詳しい方いたらコメント是非お願いします!)。
参考
Discussion