web-dev-qa-db-fra.com

Comment dupliquer un fichier stocké dans ActiveStorage dans Rails 5.2

J'ai un modèle qui utilise ActiveStorage:

class Package < ApplicationRecord
  has_one_attached :poster_image
end

Comment créer une copie d'un objet Package qui contient un doublon du fichier poster_image initial. Quelque chose dans le sens de:

original = Package.first
copy = original.dup
copy.poster_image.attach = original.poster_image.copy_of_file
15
Robban

Mettez à jour votre modèle:

class Package < ApplicationRecord
  has_one_attached :poster_image
end

Attachez le blob d'image d'affiche du package source au package de destination:

source_package.dup.tap do |destination_package|
  destination_package.poster_image.attach(source_package.poster_image.blob)
end
16
George Claghorn

Si vous souhaitez une copie complète du fichier afin que l'enregistrement d'origine et l'enregistrement cloné a sa propre copie du fichier joint, procédez comme suit:

Dans Rails 5.2, saisissez ce code et mettez-le dans config/initializers/active_storage.rb, puis utilisez ce code pour faire une copie:

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

Après Rails 5.2 (chaque fois qu'une version inclut ce commit ), alors vous pouvez simplement faire ceci:

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

Merci, George, pour votre réponse originale et pour vos Rails contributions. :)

10
Benjamin Curtis

Trouvé la réponse en parcourant les tests de Rails, en particulier dans le test de modèle de blob

Donc pour ce cas

class Package < ApplicationRecord
  has_one_attached :poster_image
end

Vous pouvez dupliquer la pièce jointe en tant que telle

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

La même approche fonctionne avec has_many_attachments

class Post < ApplicationRecord
  has_many_attached :images
end

original = Post.first
copy = original.dup

copy.images.each do |image|
  copy.images.attach io: StringIO.new(original.poster_image.download),
                     filename: original.poster_image.filename,
                     content_type: original.poster_image.content_type
end
2
jethro