Railsマイグレーションでexecuteを使う時のロールバック対応
はじめに
Rails勉強会に参加しました。
今回は、「Once/camp」のコードを読みながら、Railsマイグレーションでexecuteを使う時のロールバック対応について学習をしました。
正直勉強会の内容は全くわかりませんでしたが、大変勉強になりました。
executeを使う際は、ロールバックができないようです
Railsのマイグレーションで生SQLを実行する際、executeメソッドを使用しますが、そのままではロールバックができません。本記事では、ロールバック可能なexecuteの書き方について備忘録としてまとめます。
executeメソッドの基本
マイグレーションファイルで生SQLを実行したい場合、executeメソッドを使用
class CreateMessageSearchIndex < ActiveRecord::Migration[8.0]
def change
execute <<~SQL
CREATE VIRTUAL TABLE message_search_index
USING FTS5(content, content=messages)
SQL
end
end
しかし、この書き方ではロールバックができない
ロールバック可能にする方法
方法1: up / down を明示的に分ける
changeメソッドの代わりに、upとdownメソッドを定義
class CreateMessageSearchIndex < ActiveRecord::Migration[8.0]
def up
execute <<~SQL
CREATE VIRTUAL TABLE message_search_index
USING FTS5(content, content=messages)
SQL
end
def down
execute <<~SQL
DROP TABLE message_search_index
SQL
end
end
この方法
-
rails db:migrateを実行するとupが実行される -
rails db:rollbackを実行するとdownが実行される
方法2: reversible ブロックを使う
changeメソッドの中でreversibleブロックを使用する方法もある
class CreateMessageSearchIndex < ActiveRecord::Migration[8.0]
def change
reversible do |dir|
dir.up do
execute <<~SQL
CREATE VIRTUAL TABLE message_search_index
USING FTS5(content, content=messages)
SQL
end
dir.down do
execute <<~SQL
DROP TABLE message_search_index
SQL
end
end
end
end
この方法は
-
changeメソッドの中でアップとダウンの両方を定義できる - より明示的に処理をまとめて書ける
実務での使い分け
up / down を使うケース
- シンプルなSQL実行
- マイグレーション全体がSQL直接実行のみの場合
reversible を使うケース
-
changeメソッド内で通常のマイグレーション処理とSQL実行を混在させたい場合 - 複数の
reversibleブロックをまとめたい場合
def change
create_table :users do |t|
t.string :name
t.timestamps
end
reversible do |dir|
dir.up do
execute "CREATE INDEX ..."
end
dir.down do
execute "DROP INDEX ..."
end
end
end
まとめ
-
executeをそのまま使うとロールバックできない - ロールバック可能にするには
up/downかreversibleを使う - 実装の内容や好みに応じて使い分ける
特にSQLiteのFTS5など、Railsのマイグレーションメソッドで表現できない機能を使う場合は、必ずロールバック方法も考慮
初学者のため、間違えていたらすいません。