升级至Rails 6.1后运行RSpec时schema_migrations表条目丢失引发测试失败问题排查
看起来你在升级到Rails 6.1后,被测试环境里的数据库迁移问题折腾得不轻——尤其是schema_migrations表条目莫名丢失,一会儿提示环境信息找不到,一会儿又说迁移未完成。结合你的配置和Oracle数据库的特性,我来帮你拆解问题并给出解决方案:
核心问题定位
首先得揪出你配置里的一个关键笔误:在DatabaseCleaner.clean_with的参数里,你写的是expect: %w(ar_internal_metadata schema_migrations),但正确的参数名应该是except!这个错误直接导致DatabaseCleaner忽略了你的排除表配置,每次执行清理时都会截断所有表,包括schema_migrations和ar_internal_metadata——这就是为什么你设置完环境后,一跑测试就只剩一条迁移记录的原因。
另外,Rails 6.1新增了ar_internal_metadata表来跟踪数据库环境,Oracle默认把表名转成大写存储(你日志里的SCHEMA_MIGRATIONS就是明证),这和Rails默认的小写表名规则冲突,也会加剧这个问题。
分步解决方案
1. 修复DatabaseCleaner的配置错误
立刻修正rails_helper.rb里的笔误,把expect改成except:
config.before(:suite) do DatabaseCleaner.clean_with :truncation, except: %w(ar_internal_metadata schema_migrations) DatabaseCleaner.strategy = :transaction end
这个修改会告诉DatabaseCleaner在执行全表截断时,跳过这两个核心系统表,避免迁移记录和环境信息被误删。
2. 适配Oracle的表名大小写规则
Oracle默认将表名存储为大写,而Rails ActiveRecord默认用小写。为了避免表名不匹配的问题,你可以在config/environments/test.rb里添加以下配置:
config.active_record.table_name_prefix = '' config.active_record.table_name_suffix = '' # 让Rails生成大写的表名 config.active_record.default_table_name = lambda { |klass| klass.model_name.plural.upcase }
这样Rails在创建表时会自动使用大写名称,和Oracle的规则对齐,避免查询时找不到表的问题。
3. 彻底重置测试数据库
执行以下命令,完全重建测试环境的数据库,确保所有系统表和迁移记录都正确初始化:
# 删除测试数据库 bin/rails db:drop RAILS_ENV=test # 创建新的测试数据库 bin/rails db:create RAILS_ENV=test # 执行所有迁移 bin/rails db:migrate RAILS_ENV=test # 设置测试环境标记 bin/rails db:environment:set RAILS_ENV=test
4. 优化DatabaseCleaner的策略(可选)
对于Oracle数据库,事务策略在某些场景下(比如JS驱动的特性测试)可能会有问题。如果后续测试仍有异常,可以按测试类型调整清理策略:
config.before(:each) do # 对于需要跨连接的测试(如JS测试),用截断策略 if example.metadata[:js] || example.metadata[:type] == :feature DatabaseCleaner.strategy = :truncation, except: %w(ar_internal_metadata schema_migrations) else # 其他测试用事务策略,更快更安全 DatabaseCleaner.strategy = :transaction end end
额外检查项
- 确认你的迁移文件里没有手动操作
schema_migrations表的代码,这会干扰Rails的迁移跟踪机制。 - 保持
activerecord-oracle_enhanced-adapter版本和Rails版本兼容(你当前用的6.1.4是适配Rails 6.1的,没问题)。 - 如果
schema.rb不能很好地兼容Oracle特性,可以切换到structure.sql:执行bin/rails db:structure:dump RAILS_ENV=test,然后删除schema.rb,Rails会自动使用structure.sql来管理数据库结构。
内容的提问来源于stack exchange,提问作者Aniket Tiwari

