なんとなく使っているので、ちゃんと理解を深めようということで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