🎈

【Rails】rails db:migrate と rails db:schema:load の挙動の違い

2024/04/26に公開

はじめに

rails db:migraterails db:schema:loadの違いについて記載します。

結論

  • 何を元にマイグレーションを実行するかの違いです。
    • rails db:migrate
      • マイグレーションファイルを参照してクエリを発行。schema.rbは参照されない。マイグレーション完了後、現在のデータベーススキーマのスナップショットがschema.rbに反映される。
    • rails db:schema:load
      • schema.rbをもとにクエリを発行。マイグレーションファイルは参照されない。
  • rails db:schema:loadは既存のデータベースをリセットするので、既存のデータが全て削除される。

rails db:migrate

rails db:migrateを実行した際の流れは下記のとおりです。

① マイグレーションファイルの実行
Railsはdb/migrateディレクトリ内にあるマイグレーションファイルをタイムスタンプの順に実行する。
このプロセスでは、まだ実行されていない(schema_migrationsテーブルにそのバージョン番号が記録されていない)マイグレーションファイルのみが対象となる。
↓
② schema_migrationsテーブルの更新
マイグレーションが成功すると、そのマイグレーションのバージョン番号(マイグレーションファイル名の接頭部分にあるタイムスタンプ)がschema_migrationsテーブルに追加される。
これにより、どのマイグレーションが既に適用されたかをRailsが追跡できるようになる。
↓
③ schema.rbの更新
マイグレーションの適用が完了すると、現在のデータベーススキーマのスナップショットがschema.rbに反映される。
このファイルはマイグレーションを実行する際に直接参照されることはない。

rails db:migrateを実行した際のRailsのログを見てみます(①→②)

実行後のschema_migrationsテーブルを見てみます。(②)

MySQL
SELECT * FROM schema_migrations;
  +----------------+
  | version        |
  +----------------+
  | ...            |
  | 20240319010635 |
  +----------------+

rails db:schema:load

rails db:schema:loadを実行した際の流れは下記のとおりです。

① データベースのリセット
db:schema:load は既存のデータベーススキーマ(存在する場合)を完全に無視し、schema.rb に定義されているスキーマ定義に基づいてデータベースを一から構築する。
このコマンドを実行すると、すでに存在するテーブルは削除され、新たに schema.rb に記述されている内容でテーブルが作成される。
↓
② schema.rb の利用
schema.rb ファイルが読み込まれ、その中に記述されているすべてのテーブル定義とスキーマ情報がデータベースに適用される。
schema.rb は、最後に成功したマイグレーションの状態を表しているため、db:schema:load でデータベースを構築すると、
マイグレーションを一つ一つ適用することなく、直接最新のスキーマ状態になる。
↓
③ schema_migrations テーブルの更新
schema.rb をもとにデータベーススキーマが再構築されると同時に、schema_migrations テーブルも更新される。
schema_migrations テーブルには、schema.rb に基づく最後のマイグレーションのバージョン番号が保存される。
これにより、将来的に rails db:migrate を実行した際に、どのマイグレーションから開始すればよいかがRailsによって識別される。

※ マイグレーションファイルの無視
db:schema:load コマンドは、マイグレーションファイルを一切参照しない。
マイグレーションファイルを実行するのではなく、schema.rb が持つスキーマ情報を直接データベースに適用する。

どう使い分けるのか

  • rails db:schema:loadは既存のデータを全て削除してしまうので、もちろん本番環境では使わない。
  • 下記の記事にこんなことが書いてあった。なるほど..!

    ローカルでは rake db:migrete , CIツール上では rake db:schema:load と使い分けるのが一般的で、そうすることによってmigrateし忘れてpushしてもCIツール上のschema.rbのバージョンが同じになるようにしてるみたい。

https://euglena1215.hatenablog.jp/entry/2016/08/17/184301

  • rails db:schema:loadschema.rbから直接マイグレーションを行うので、ローカルで新しい開発環境のセットアップをしたいときは良さそう。
株式会社リンクエッジ

Discussion