Rspec で Rails の移行をテストするときにインデックスを同時に削除する
概要
postgresデータベースのRails ActiveRecordを使用した新しい移行をテストするためのRspecテストを作成しています。移行ファイルは同時にインデックスを追加するため、私の移行には以下が含まれます。
disable_ddl_transaction!
add_index :table_name, [:column_1, :column_2], algorithm: :concurrently
移行の実行やロールバックに問題はありません。しかし、仕様ファイルを作成しているときに、インデックスの削除を含む以前の移行に戻す必要があり、次のエラーが発生します。
ActiveRecord::StatementInvalid:
PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block
: SELECT pg_advisory_unlock(7815322980726126075)
# ./spec/migrations/<FILE_NAME>.rb:17:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# PG::ActiveSqlTransaction:
# ERROR: DROP INDEX CONCURRENTLY cannot run inside a transaction block
開発段階では移行をロールバックできるのに、テスト環境でこの postgres エラーが発生する理由を理解しようとしています。
編集:これは、仕様ファイル内の目的の移行にロールバックする方法です。これがエラーを生成するものです。
before :each do
ActiveRecord::MigrationContext.new(migration_paths).migrate(previous_version)
ConferenceLink.reset_column_information
end
解決策
Rails-rspec にはデフォルト設定があり、各サンプルを独自のデータベース トランザクションで実行します。通常、サンプルの後にロールバックされ、次のサンプルで再びデータベースがクリーンになるようにします。
rspec-rails でこれらのトランザクションをグローバルに無効にすることができます。
RSpec.configure do |c|
c.use_transactional_examples = false
end
ただし、各テストで実行している変更が他のテストの既存のデータベースに影響を与えないことを手動で確認する必要があります。 after ブロックでクリーンアップを実行するか、データベース クリーナー gem のようなものを使用します。
詳細と例についてはドキュメントを参照してください。