我正在尝试播种我的开发数据库。其中一个型号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'
...
型
我有一种感觉,有一种方法可以用多个附件来播种一行。
是什么原因导致这个错误?为什么我可以附加一次图像,但不能多次?
4条答案
按热度按时间8oomwypt1#
在我的例子中,我注意到的是,当在事务中使用ActiveStorage附加附件时,它无法正常工作。这适用于迁移,种子或回调。为了避免我的逻辑被 Package 在事务中,我最终做的是在线程中运行逻辑:
字符串
2izufjch2#
我不能完全重现你的问题(我一直得到
ActiveStorage::IntegrityError
异常而不是ActiveStorage::FileNotFoundError
),但我想我知道发生了什么。字符串
image_file
的当前位置将在文件的末尾。现在,当Active Storage尝试再次读取文件时,它不会获得任何数据,因此校验和失败(我的IntegrityError
)或Active Storage认为那里没有文件(您的FileNotFoundError
)。解决方案是通过调用
#rewind
将文件位置重置回开头:型
您可以在
project.images.attach
调用之前或之后image_file.rewind
,倒带新打开的文件不会做任何有趣的事情。#rewind
并不总是被您传递给#attach
的io
支持(或需要),因此Active Storage本身不能真正做到这一点。或者,您可以在每次迭代时打开该文件:
型
我假设在你的问题中缺少的
times
块的do
只是一个错字。uubf1zoe3#
我通过简单地使用数组作为参数来实现它:
字符串
vshtjzan4#
我也有一个IO进程将文件附加到一个事务中。我的代码在我的开发计算机上工作,但在AWS上失败。Pere关于使用
Thread.new
的回答也解决了我的问题(几乎)。在使用Thread.new后,我发现有时附件会默默地失败。仔细想想,我想让IO进程在
transaction do
块中运行是非常糟糕的做法-我们希望尽可能快地完成事务块,以免阻塞数据库。我切换到触发
.attach
作为一个后台作业,所以在交易过程中,我调用一个方法,该方法调用文件,以便稍后在一个单独的作业中附加。对我来说,成功的文件上传不是停止整个交易的标准。我推荐这种方法用于任何可以负担得起的应用程序。