You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RSpec请求测试ActiveStorage与FactoryBot报错:签名不匹配

解决RSpec请求测试中ActiveStorage+FactoryBot的签名错误问题

这个错误的核心原因是:你直接把FactoryBot工厂里定义的Rack::Test::UploadedFile对象当作参数传给PATCH请求时,Rack::Test会把这个对象序列化为字符串(就是日志里看到的#<Rack::Test::UploadedFile:0x0000000122758d98>),而非正确识别为上传文件,导致后端收到的不是ActionDispatch::Http::UploadedFile实例,触发ActiveStorage的签名验证失败。

下面是具体的解决方法:

方法一:测试用例中手动构造上传参数(最直接有效)

不要从FactoryBot生成的用户实例里取picture属性,而是在测试代码里单独创建Rack::Test::UploadedFile实例,直接传入请求参数:

# 测试文件内
let(:test_image) { Rack::Test::UploadedFile.new(Rails.root.join('spec', 'fixtures', 'files', 'avatar.jpg'), 'image/jpeg') }

it "成功更新用户头像" do
  patch user_path(target_user), params: { user: { picture: test_image } }
  # 这里写你的断言逻辑,比如检查头像是否成功附加
end

这样Rack::Test会自动识别这是上传文件,将其转为ActionDispatch::Http::UploadedFile传给后端,匹配浏览器上传的格式。

方法二:调整FactoryBot工厂的用途

如果想复用上传文件的逻辑,不要在工厂里直接定义picture属性(因为ActiveStorage的附件不是普通模型属性),而是用trait来生成已附加图片的用户实例,供测试中作为初始状态使用:

# factories/users.rb
FactoryBot.define do
  factory :user do
    name { "测试用户" }
    # 其他基础属性...

    trait :with_picture do
      after(:build) do |user|
        user.picture.attach(
          io: File.open(Rails.root.join('spec', 'fixtures', 'files', 'avatar.jpg')),
          filename: 'avatar.jpg',
          content_type: 'image/jpeg'
        )
      end
    end
  end
end

测试更新场景时,还是用方法一的方式手动构造上传参数,这个trait仅用来生成已有头像的用户,方便测试更新前后的状态对比。

额外注意事项

  • 确保测试用的文件路径正确,比如spec/fixtures/files下确实存在对应的测试图片,避免文件找不到的问题。
  • 不需要手动设置multipart/form-data请求头,只要参数里有Rack::Test::UploadedFile实例,Rack::Test会自动处理请求格式。

内容的提问来源于stack exchange,提问作者user502052

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:56:06