ActiveRecord::Migration.maintain_test_schema! 测试迁移异常成因咨询
问题根本成因解析
核心触发逻辑
ActiveRecord::Migration.maintain_test_schema!的设计逻辑是优先同步db/schema.rb(或db/structure.sql)到测试库,而非通过执行增量迁移完成schema对齐,运行时的完整流程如下:
- 对比开发环境和测试环境的schema版本号
- 若版本不一致,会先清空测试库所有表(包括记录迁移执行状态的
schema_migrations表) - 从头加载完整的schema文件到测试库,加载完成后自动重建
schema_migrations表并写入所有已执行迁移的版本号
报错的根本原因
出现对应报错的原因是上述流程被中断导致的中间态问题:
- 当
maintain_test_schema!已经执行完「清空测试库所有表、删除schema_migrations表」的步骤,但还没完成schema文件加载、重建schema_migrations表的操作时,进程被中断(比如手动终止RSpec运行、schema文件损坏加载失败),就会进入测试库中业务表残留、但schema_migrations表不存在的中间状态 - 此时执行
rails db:migrate RAILS_ENV=test,ActiveRecord检测不到schema_migrations表,会默认判定为首次执行迁移,从编号最小的迁移开始全量执行,自然会触发Relation table_name already exists的报错 - 此时查询迁移状态时返回
Schema migrations table does not exist yet.也完全符合这个中间态的特征
两种临时方案生效的逻辑
- 先执行测试环境迁移再运行RSpec:手动执行
rails db:migrate RAILS_ENV=test时会先创建schema_migrations表,全量执行完所有迁移后schema状态完整,maintain_test_schema!检测到版本对齐,不会触发清空重载schema的逻辑,因此运行正常 - 执行
rails db:migrate:reset RAILS_ENV=test生效:该命令会先删除重建整个测试库,再从头执行所有迁移,直接覆盖了中间态的异常数据,冲突自然消失
推荐最佳实践
Rails测试环境的设计逻辑是和schema.rb/structure.sql对齐,不需要手动执行迁移,遇到上述中间态问题时,直接执行rails db:schema:load RAILS_ENV=test即可快速修复,比全量跑迁移效率更高。
内容的提问来源于stack exchange,提问作者Lidia Mokevnina
相关产品推荐
相关产品推荐

