Search code examples
ruby-on-railsrubypostgresqlactiverecord

Drop index concurrently when testing Rails migration in Rspec


I'm writing an Rspec test to test a new migration with Rails ActiveRecord for a postgres database. The migration file adds an index concurrently, and so my migration includes:

disable_ddl_transaction!

add_index :table_name, [:column_1, :column_2], algorithm: :concurrently

No issues running the migration or rolling it back. But when I'm writing my spec file, I need to revert to the previous migration, which includes dropping the index, and I'm hitting this error:

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

Trying to understand why I'm able to roll the migration back in development but hitting this postgres error in my test environment.

EDIT: This is how I'm rolling back to the desired migration in my spec file, which is what's producing the error:

before :each do
  ActiveRecord::MigrationContext.new(migration_paths).migrate(previous_version)
  ConferenceLink.reset_column_information
end

Solution

  • rails-rspec has a default configuration which causes it to run each example in its own database transaction, which is usually rolled back after an example so that the database is clean for the next examples again.

    You can globally disable these transactions in rspec-rails:

    RSpec.configure do |c|
      c.use_transactional_examples = false
    end
    

    However, then you have to manually make sure that the changes you are performing in each test do not affect the existing database for the other tests, e.g. by running cleanups in an after block or/ using something like the database-cleaner gem.

    Please see the documentation for details and examples.