30

我有一个使用 ActiveStorage 的模型:

class Package < ApplicationRecord
  has_one_attached :poster_image
end

如何创建包含初始 poster_image 文件副本的 Package 对象的副本。类似于以下内容:

original = Package.first
copy = original.dup
copy.poster_image.attach = original.poster_image.copy_of_file
4

6 回答 6

31

更新您的模型:

class Package < ApplicationRecord
  has_one_attached :poster_image
end

将源包的海报图像 blob 附加到目标包:

source_package.dup.tap do |destination_package|
  destination_package.poster_image.attach(source_package.poster_image.blob)
end
于 2018-04-04T16:17:19.917 回答
16

如果您想要文件的完整副本,以便原始记录克隆记录都有自己的附件副本,请执行以下操作:

在 Rails 5.2 中,获取这段代码并将其放入 中config/initializers/active_storage.rb,然后使用这段代码进行复制:

ActiveStorage::Downloader.new(original.poster_image).download_blob_to_tempfile do |tempfile|
  copy.poster_image.attach({
    io: tempfile, 
    filename: original.poster_image.blob.filename, 
    content_type: original.poster_image.blob.content_type 
  })
end

在 Rails 5.2 之后(只要一个版本包含这个 commit),那么你可以这样做:

original.poster_image.blob.open do |tempfile|
  copy.poster_image.attach({
    io: tempfile, 
    filename: original.poster_image.blob.filename, 
    content_type: original.poster_image.blob.content_type 
  })
end

感谢 George,您的原始答案和 Rails 贡献。:)

于 2018-07-03T19:07:14.777 回答
10

通过查看 Rails 的测试找到答案,特别是在 blob 模型测试中

所以对于这种情况

class Package < ApplicationRecord
  has_one_attached :poster_image
end

您可以这样复制附件

original = Package.first
copy = original.dup
copy.poster_image.attach \
  :io           => StringIO.new(original.poster_image.download),
  :filename     => original.poster_image.filename,
  :content_type => original.poster_image.content_type

同样的方法适用于has_many_attachments

class Post < ApplicationRecord
  has_many_attached :images
end

original = Post.first
copy = original.dup

original.images.each do |image|
  copy.images.attach \
    :io           => StringIO.new(image.download),
    :filename     => image.filename,
    :content_type => image.content_type
end
于 2019-03-21T19:30:09.407 回答
4

在 rails 5 Jethro 的回答效果很好。对于 Rails 6,我必须修改为:

  image_io = source_record.image.download
  ct = source_record.image.content_type
  fn = source_record.image.filename.to_s
  ts = Time.now.to_i.to_s

  new_blob = ActiveStorage::Blob.create_and_upload!(
    io: StringIO.new(image_io),
    filename: ts + '_' + fn,
    content_type: ct,
  )

  new_record.image.attach(new_blob)

资源:

于 2020-05-18T14:14:47.447 回答
4

它对我有用:

copy.poster_image.attach(original.poster_image.blob)
于 2020-10-27T10:19:32.007 回答
4

本杰明的回答略有不同确实对我有用。

copy.poster_image.attach({
    io: StringIO.new(original.poster_image.blob.download), 
    filename: original.poster_image.blob.filename, 
    content_type: original.poster_image.blob.content_type 
  })

于 2021-02-24T17:42:28.663 回答