【问题标题】:Why do I get `ActiveStorage::FileNotFoundError` when trying to seed the db with attachments?尝试使用附件为数据库播种时,为什么会出现“ActiveStorage::FileNotFoundError”?
【发布时间】:2019-03-09 15:01:56
【问题描述】:

我正在尝试为我的开发数据库播种。其中一个模型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'
...

我觉得有一种方法可以用多个附件播种一行。

是什么导致了这个错误?为什么我只能附上一张图片,但不能附上多次?

【问题讨论】:

  • 你不需要多次打开文件
  • 我已经更新了代码以确保我只打开文件一次。但是,多次尝试附加文件时仍然会出现错误。

标签: ruby-on-rails rails-activestorage


【解决方案1】:

我无法完全重现您的问题(我不断收到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 只是一个错字顺便说一句。

【讨论】:

    【解决方案2】:

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

    Thread.new do
      # your logic here
    end.join
    

    【讨论】:

    • 这正是发生在我身上的事情。感谢您分享这个答案!
    【解决方案3】:

    我通过简单地使用数组作为参数让它工作:

    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
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多