ruby-on-rails 为什么我在尝试用附件播种数据库时会得到`ActiveStorage::FileNotFoundError`?

suzh9iv8  于 9个月前  发布在  Ruby
关注(0)|答案(4)|浏览(112)

我正在尝试播种我的开发数据库。其中一个型号Project有与之关联的图像。
我在./db/seed_files/中放置了一个占位符图像。我的种子文件看起来像这样:

# Add projects
1000.times do
  project = Project.new(
    name: Faker::Marketing.buzzwords.capitalize,
    description: Faker::Lorem.sentence(rand(1..30))
  )
  image_file = File.open("./db/seed_files/placeholder_image.png")
  project.images.attach(io: image_file, filename: "placeholder_image.png", content_type: "image/png")
  project.save
end

字符串
这运行良好。它为每个项目附加一个图像。
然而,我想种子与多个图像每个项目。我想我可以附加相同的图像多次。
我试过:

# Add projects
1000.times do
  project = Project.new(
    name: Faker::Marketing.buzzwords.capitalize,
    description: Faker::Lorem.sentence(rand(1..30))
  )
  image_file = File.open("./db/seed_files/placeholder_image.png")
  rand(1..3).times do
    project.images.attach(io: image_file, filename: "placeholder_image.png", content_type: "image/png")
  end
  project.save
end


但这会导致错误:ActiveStorage::FileNotFoundError

/Users/greidods/.rvm/gems/ruby-2.6.1/bundler/gems/rails-b366be3b5b28/activestorage/lib/active_storage/service/disk_service.rb:136:in `rescue in stream'
/Users/greidods/.rvm/gems/ruby-2.6.1/bundler/gems/rails-b366be3b5b28/activestorage/lib/active_storage/service/disk_service.rb:129:in `stream'
/Users/greidods/.rvm/gems/ruby-2.6.1/bundler/gems/rails-b366be3b5b28/activestorage/lib/active_storage/service/disk_service.rb:28:in `block in download'
/Users/greidods/.rvm/gems/ruby-2.6.1/bundler/gems/rails-b366be3b5b28/activesupport/lib/active_support/notifications.rb:180:in `block in instrument'
/Users/greidods/.rvm/gems/ruby-2.6.1/bundler/gems/rails-b366be3b5b28/activesupport/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
...


我有一种感觉,有一种方法可以用多个附件来播种一行。
是什么原因导致这个错误?为什么我可以附加一次图像,但不能多次?

8oomwypt

8oomwypt1#

在我的例子中,我注意到的是,当在事务中使用ActiveStorage附加附件时,它无法正常工作。这适用于迁移,种子或回调。为了避免我的逻辑被 Package 在事务中,我最终做的是在线程中运行逻辑:

Thread.new do
  # your logic here
end.join

字符串

2izufjch

2izufjch2#

我不能完全重现你的问题(我一直得到ActiveStorage::IntegrityError异常而不是ActiveStorage::FileNotFoundError),但我想我知道发生了什么。

project.images.attach(io: image_file, filename: "placeholder_image.png", content_type: "image/png")

字符串
image_file的当前位置将在文件的末尾。现在,当Active Storage尝试再次读取文件时,它不会获得任何数据,因此校验和失败(我的IntegrityError)或Active Storage认为那里没有文件(您的FileNotFoundError)。
解决方案是通过调用#rewind将文件位置重置回开头:

rand(1..3).times do
  project.images.attach(io: image_file, filename: "placeholder_image.png", content_type: "image/png")
  image_file.rewind
end


您可以在project.images.attach调用之前或之后image_file.rewind,倒带新打开的文件不会做任何有趣的事情。#rewind并不总是被您传递给#attachio支持(或需要),因此Active Storage本身不能真正做到这一点。
或者,您可以在每次迭代时打开该文件:

rand(1..3).times do
  image_file = File.open("./db/seed_files/placeholder_image.png")
  project.images.attach(io: image_file, filename: "placeholder_image.png", content_type: "image/png")
end


我假设在你的问题中缺少的times块的do只是一个错字。

uubf1zoe

uubf1zoe3#

我通过简单地使用数组作为参数来实现它:

image_file = File.open("./db/seed_files/placeholder_image.png")
files = []
  rand(1..3).times do
    files << {io: image_file, 
              filename: "placeholder_image.png",
              content_type: "image/png"
             }
    project.images.attach(files)
  end

字符串

vshtjzan

vshtjzan4#

我也有一个IO进程将文件附加到一个事务中。我的代码在我的开发计算机上工作,但在AWS上失败。Pere关于使用Thread.new的回答也解决了我的问题(几乎)。
在使用Thread.new后,我发现有时附件会默默地失败。仔细想想,我想让IO进程在transaction do块中运行是非常糟糕的做法-我们希望尽可能快地完成事务块,以免阻塞数据库。
我切换到触发.attach作为一个后台作业,所以在交易过程中,我调用一个方法,该方法调用文件,以便稍后在一个单独的作业中附加。对我来说,成功的文件上传不是停止整个交易的标准。我推荐这种方法用于任何可以负担得起的应用程序。

相关问题