RSpec特性测试中Paper Trail的whodunnit字段无法保存问题
我之前在项目里也踩过PaperTrail测试环境的这个坑,结合你说的情况——生产环境一切正常,测试里变更记录的其他字段都能存,唯独whodunnit是空的,而且已经配置了versioning: true和set_paper_trail_whodunnit——给你几个实际可行的排查方向:
1. 先确认测试里current_user真的被正确登录了
你提到控制器里有current_user方法,但测试场景下很容易忽略「用户未登录」这个点。比如在特性测试里,你得先确保执行变更操作前,用户已经通过sign_in(如果用Devise)或者自定义登录逻辑处于登录状态:
# 特性测试示例:先创建并登录用户 before do @test_user = create(:user) sign_in @test_user # 用Devise的话就这么写,自定义登录逻辑就换成你的方法 end scenario "更新资源时正确记录操作人" do # 这里写你的资源更新步骤 expect(Version.last.whodunnit).to eq(@test_user.id.to_s) end
PaperTrail的set_paper_trail_whodunnit默认是取current_user.id转成字符串存的,如果测试里current_user是nil,那whodunnit自然是空的。
2. 手动设置whodunnit验证是否能存入
可以先绕开current_user,在测试前手动给PaperTrail设置whodunnit,看看能不能正常保存:
before do PaperTrail.request.whodunnit = "test_user_456" end scenario "手动设置whodunnit测试" do # 执行资源变更操作 expect(Version.last.whodunnit).to eq("test_user_456") end
如果这个测试能过,说明问题出在set_paper_trail_whodunnit没正确拿到current_user;如果还是不行,那大概率是测试环境的PaperTrail配置有问题。
3. 检查set_paper_trail_whodunnit是否真的被执行了
你说已经在ApplicationController加了before_action :set_paper_trail_whodunnit,但可以临时加个日志验证一下这个方法在测试里有没有被调用:
# 在ApplicationController里临时加一行日志 def set_paper_trail_whodunnit Rails.logger.info "=== PaperTrail whodunnit: current_user id is #{current_user&.id} ===" super end
然后运行测试,看日志里有没有输出用户ID。如果没输出,要么是测试用的控制器没继承ApplicationController,要么是有地方用了skip_before_action跳过了这个回调。
4. 检查测试环境的PaperTrail初始化配置
有时候测试环境的initializer可能有特殊配置,比如不小心关了whodunnit记录?打开config/initializers/paper_trail.rb,确保测试环境没有设置类似whodunnit: false的配置。也可以在测试里打印下PaperTrail的配置看看:
scenario "查看PaperTrail配置" do puts PaperTrail.config.inspect end
确认whodunnit相关的配置是开启状态。
5. 再确认测试数据库的迁移是否同步
虽然你说数据库有whodunnit列,但保险起见,再跑一遍测试数据库的迁移:
rails db:test:prepare # 或者 rails db:migrate RAILS_ENV=test
确保测试库的versions表结构和生产库完全一致,避免因为迁移没同步导致字段无法写入。
内容的提问来源于stack exchange,提问作者codenoob

