Я пишу тест Rspec для проверки новой миграции с помощью Rails ActiveRecord для базы данных postgres. Файл миграции одновременно добавляет индекс, поэтому моя миграция включает в себя:
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
или используя что-то вроде Database-Cleaner gem.
Подробности и примеры см. в документации.
Убедитесь, что стратегия data_cleaner также использует что-то другое, кроме :transaction
.
Спасибо! Верно. Это сработало DatabaseCleaner.clean_with(:truncation)
Спасибо! К счастью,
database-cleaner
уже настроен в приложении. Я обновляю конфигурацию в спецификации и добавляю тудаbyebug
, чтобы подтвердить, чтоRSpec.configuration.use_transactional_examples
оценивается какfalse
внутри примера. Все еще выскакивает та же ошибка PG. Вот как я откатываюсь к нужной миграции внутри спецификации:ActiveRecord::MigrationContext.new(migration_paths).migrate(previous_version)
. Я выполняю это внутри блокаbefore :each
, но сталкиваюсь с той же ошибкой, если перемещаю его прямо внутри примера.