🎒

(Rails)実務でmigrateファイルを扱って調べたこと諸々。add refence vs add foreign_keyなど

2024/01/29に公開

実務でmigrateファイルを新規追加したのでその時に調べたことや試したことをメモしておく。
migrateファイルは個人開発でしか書いたことがなかったし、それも数年前だったので復習も兼ねて
migrateファイルに関してメモを残す。

migrationとは、SQLを使わずにスキーマ(DBのテーブルやカラムなどの構造)を変更できる手法。

Active Recordの機能の一つ。生のSQLを書かずにRubyの記法で書くことができる。
https://railsguides.jp/active_record_migrations.html

migrationファイルの作成方法は2種類。

# 1.モデル生成
bin/rails g model クラス名 or テーブル名
# model, migration, model spec, factoriesの4つのファイルを作成

# 2.migrateファイル生成
bin/rails g migration クラス名
# migrationファイルのみを生成

クラス名の後ろにfieldを追加することも可能。
クラス名は複数形にするのがデフォルトのよう。

migrationファイルを削除するときは必ずrollbackしてから

ちゃんとrollbackしてからでないと、NO FILEになってしまう。
マイグレーションが実行されたのにdb/migrate/ディレクトリ配下に存在しない場合に表示される。
NO FILEになった場合の対処は同じファイル名のmigrationファイルを作り直さないといけないので少し面倒。
https://qiita.com/ISSO33/items/33a935cb3255c269bef2

db:migrate:resetとdb:resetの挙動の違い

どちらもDBを再生成した後にスキーマの定義までを実施するが、
前者はmigrateファイルを元にスキーマを定義する。後者はschema.rbを元に定義する。
さらに後者はseedデータも読み込む。
https://otaku-programmer.com/rails/db/migration/1/

db:migrate:reset

  1. db:drop
  2. db:create
  3. db:migrate

db:reset

  1. db:drop
  2. db:create
  3. db:seed(?)
    →実際に試した後、DBを見るとseedデータは読み込まれていなかった。(schema_migration, ar_internal_metadataというテーブルには登録されていた?)
    私が今回試したプロダクトはなんらかの設定を施していて、db:reset実行時にseedを読み込まないようにしていたのかも。

schema_migration, ar_internal_metadata

resetした後に見つけたテーブル。migrateを実行すると自動的に生成されるテーブル。

schema_migrationは、migrationのタイムスタンプを保持するためのテーブルで、migrateするときは本ファイルを参照することで、変更分のみmigrateを行うことができる(と考えられる)。

例えば、以下のようなmigrationファイルがあったとすると、
20190701165640_create_articles.rb
schema_migrationには、以下のレコードが登録される。
20190701165640

これにより、migrate済みのファイルを管理できる。既にmigrateしているならmigrateを実行しない、ということが可能。
https://tushartuteja.medium.com/demystifying-rails-migrations-53abcf3a7ddd
https://railsguides.jp/active_record_migrations.html#古いマイグレーション

ar_internal_metadataは、自身のRails環境とスキーマに関する情報を保存するテーブル。
DBを意図せず削除されることを防止するためのテーブル。
このテーブルには、RAILS_ENVの情報を保持しており、environmentがproductionの場合はエラーとするために必要らしい。
https://qiita.com/EastResident/items/53c24340fd322758901f

防止の対象となるのは、下記を参考。drop以外はあまり使わなそう。
https://www.tumblr.com/y-yagi/142064773890/rails-5に入ったdb破壊系taskの防止処理について

初期設定でオフにすることも可能。
https://railsguides.jp/configuring.html#メタデータストレージを設定する

add reference or add foreign key

別記事にまとめる。追加する制約が異なる。

互いの外部キーを持つテーブルのmigrateの書き方

互いに外部キーを持つリレーションの場合、先に定義するmigrateファイルは外部キー制約をつけることができない。存在しないテーブルの外部キーを持つことができないため。
この場合、両方のテーブルを定義した後に、外部キー制約を付与すれば良い。

具体な手法としては前述のadd reference等の方法があるが、迷いどころもある。
カラムを作っておいて外部キー制約だけを後付けするのか、カラムごと後で追加するか、というポイント。

文字数制限の定義方法

t.string name, limit: 20
t.integer huge_number, limit: 2.megabytes

stringなら文字数で、textやintegerはバイト数で定義する必要がある。
https://api.rubyonrails.org/v7.1/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column

Active Record5.1からidカラムの型はデフォルトでbigintに変更された。

5.0以前はidカラムの型のデフォルトはintegerだったが、5.1からはbigintとなった。
外部キー制約を付与するときは、カラムの型が一致していなければならないため、
5.0以前なのか、5.1以降なのかをケアしてあげる必要がある。

https://qiita.com/hinako_n/items/e758d58e15a3bb24a7bc
https://autovice.jp/articles/176
https://kamihikouki.hatenablog.com/entry/2017/04/11/141447
https://api.rubyonrails.org/v7.1/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference

Discussion