Rails 和 Active Storage,如何直接在创建调用上分配附件?

Rails and Active Storage, how to assign attachment directly on the create call?

MyModel 有:

has_one_attached :video

我知道我能做到:

my_model = MyModel.create!()
my_model.video.attach(io: File.open("path/my_video.webm"), filename: "video.webm")

它工作正常。

但我想知道是否有一种方法可以将附件分配到 create() 调用中,例如:

MyModel.create!(
  video: File.read("path/my_video.webm")
)

如果我执行上述操作,我会看到此错误:

/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-6.1.4.1/lib/active_support/message_verifier.rb:176:in `verify': ActiveSupport::MessageVerifier::InvalidSignature (ActiveSupport::MessageVerifier::InvalidSignature)

我试过这个:

MyModel.create!(
  video: File.open("path/my_video.webm")
)

我收到这个错误:

/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activestorage-6.1.4.1/lib/active_storage/attached/changes/create_one.rb:74:in `find_or_build_blob': Could not find or build blob: expected attachable, got #File:/Users/fernando.guillen/Development/PlaycocolaBackend/test/fixtures/files/video.webm (ArgumentError)

您可以通过创建 ActionDispatch::Http::UploadedFile 的实例来实现。这基本上只是一个临时文件实例的包装器,Rails 在处理文件上传时在内部使用它。

MyModel.create!(
  video: ActionDispatch::Http::UploadedFile.new(
    tempfile: File.open("path/my_video.webm"), 
    filename: "video.webm",
    content_type: 'video/webm'
  )
)

就效率或LOC而言,它实际上并没有比调用.attach有任何优势。尽管在 JSON.

中处理作为 base64 编码字符串传递的文件是一个绝妙的技巧

此的“真实”用例:使用 factories 创建记录,在创建时验证附件的存在。

您可以为此使用 Rack::Test::UploadedFile

FactoryBot.define do
  factory :my_model do
    video { Rack::Test::UploadedFile.new(Rails.root.join("path", "my_video.webm"), "video/webm") }
  end
end