なんとなく使っているので、ちゃんと理解を深めようということでRailsガイドを読んでまとめてみようと思います。
マイグレーションとは
Railsガイドより引用
マイグレーションは、データベーススキーマの継続的な変更(英語)を、統一的かつ簡単に行なうための便利な手法です。マイグレーションではRubyのDSLが使われているので、生のSQLを作成する必要がなく、スキーマおよびスキーマ変更がデータベースに依存しなくなります。
個別のマイグレーションは、データベースの新しい「バージョン」とみなせます。スキーマは空の状態から始まり、マイグレーションによる変更が加わるたびにテーブル、カラム、エントリが追加または削除されます。Active Recordはマイグレーションの時系列に沿ってスキーマを更新する方法を知っているので、履歴のどの時点からでも最新バージョンのスキーマに更新できます。Active Recordはdb/schema.rbファイルを更新し、データベースの最新の構造と一致するようにします。
マイグレーションファイル
マイグレーションファイルは、db/migrate
フォルダ内にある。
ファイル名は、YYYYMMDDHHMMSS_create_tasks.rb
のような形式。
前半部分YYYYMMDDHHMMSS
は、マイグレーションを識別するUTCタイムスタンプ
後半部分create_tasks
は、マイグレーション名
ファイルの後半部分(snake_case)create_tasks
は、マイグレーションのクラス名(CamelCase)CreateTasks
と一致する必要がある。
class CreateTasks < ActiveRecord::Migration[7.0]
end
作成
マイグレーションファイルは、以下のコマンド実行時にdb/migrate
フォルダに作成される。
モデルを作成したとき
rails generate model モデル名
モデルを作成した時には、YYYYMMDDHHMMSS_create_モデル名s.rb
が作成される。
個別にマイグレーションファイルを作成したとき
rails generate migration マイグレーションのクラス名
個別にマイグレーションファイルを作成したときは、YYYYMMDDHHMMSS_マイグレーションのクラス名(snake_case).rb
が作成される。
編集
change
def change
# 変更を記述
end
change
メソッドを使用すると、ActiveRecordがマイグレーションをロールバックする方法を自動的に認識してくれる。
change_column
など不可逆的なものもあるので、注意すること。
change_column :products, :part_number, :text
上記の例ではpart_number
をtext型に変更しているが、この記述からは変更前の型が分からないのでロールバックできない。( = 不可逆的)
change
メソッドでサポートされている可逆的なメソッドはRailsガイドv7.0 3.9 changeメソッドを使う
を参照。
不可逆的なメソッドを使用する場合は、reversible
メソッドを使用するか、up
/down
メソッドを使用し、明示的に通常通りに実行される処理とロールバックするときに実行する処理を指定する必要がある。
reversible
reversible
を使用すると、change
メソッド内で不可逆的な処理を記述する際に、通常通りマイグレーションする場合とロールバックする場合の処理を分けることができる。
class ExampleMigration < ActiveRecord::Migration[7.0]
def change
create_table :distributors do |t|
t.string :zipcode
end
reversible do |dir|
dir.up do
# CHECK制約を追加
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5) NO INHERIT;
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
end
end
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
end
このマイグレーションをロールバックした場合、down
ブロックはカラムの削除とテーブルの削除の間に実行される。
up
/down
def up
# 通常の変更を記述
end
def down
# upメソッドで行った変更をロールバックする処理を記述
end
up
にはスキーマに対する変更方法を、down
にはup
メソッドによって行われた変更をロールバックする方法を記述する。
class ExampleMigration < ActiveRecord::Migration [7.0]
def up
create_table :distributors do |t|
t.string :zipcode
end
# CHECK制約を追加
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5);
SQL
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
def down
rename_column :users, :email_address, :email
remove_column :users, :home_page_url
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
drop_table :distributors
end
end
up
メソッドでは、
- テーブルの作成
- CHECK制約を追加
- カラムを追加
- カラム名を変更
down
メソッドでは、
- カラム名を変更
- カラムを削除
- CHECK制約を削除
- テーブルの削除
が行われる。(reversible
に記載のマーグレーションと同等の内容)
down
メソッド内の処理の順序は、up
メソッド内の処理順と真逆にする。
その他のメソッド
その他add_column
, create_table
などのメソッドは書き出すと長くなりそうなので以下を参照。
ActiveRecord::ConnectionAdapters::SchemaStatements Methods
実行
以下のコマンドでマイグレーションを実行できる
rails db:migrate
未実行のマイグレーションファイルが複数存在する場合は、ファイル名のタイムスタンプが古い順に実行される。
特定のバージョンまでマイグレーションを実行するには以下のようにバージョンを指定する。
rails db:migrate VERSION=YYYYMMDDHHMMSS
指定したバージョンが現在のバージョンより大きい場合、指定バージョンに到達するまでchange
メソッド、up
メソッドが実行される。
(指定バージョンのマイグレーションファイルも実行される)
指定したバージョンが現在のバージョンより小さい場合、指定バージョンに到達するまでロールバックされる。
(指定バージョンのマイグレーションファイルは実行されない)
db/schema.rb
db:migrate
を実行するとdb:schema:dump
コマンドも同時に呼び出され、db/schema.rb
の内容がデータベースの構造と一致するように更新される。
db/schema.rb
にバージョンが含まれているので、version: 2023_02_28_130514
を見ればどのマイグレーションファイルまで実行されているかが確認できる。
ActiveRecord::Schema[7.0].define(version: 2023_02_28_130514) do
ロールバック
マイグレーションファイルに誤りがあり訂正したい場合など、直前に行ったマイグレーションをロールバックするには以下のコマンドを実行する。
rails db:rollback
このコマンドによりchange
メソッドを逆転実行するか、down
メソッドを実行する形で直前のマイグレーションにロールバックする。
2つ以上のマイグレーションをロールバックするには、STEP
パラメータでロールバックする数を指定する。
以下のコマンドで最後に行った3つのマイグレーションをロールバックできる。
rails db:rollback STEP=3
データベースを設定する
rails db:setup
このコマンドにより、以下がまとめて実行される
- データベースの作成
db:create
- スキーマの読み込み
db:schema:load
- seedデータを用いたデータベースの初期化
db:seed
データベースをリセットする
rails db:reset
データベースをdropして、再度設定する。(rails db:drop db:setup
と同等)
このコマンドは現在のdb/schema.rb
をそのまま使い回すので、マイグレーションファイルを編集していてもその内容は反映されない。
マイグレーションファイルの内容を反映させるには、次のコマンドを実行する。
rails db:migrate:reset
参考文献
Railsガイド v7.0 - Active Record マイグレーション
ActiveRecord::ConnectionAdapters::SchemaStatements