Reputation: 287530
I need to copy a file from one carrier wave object to another. They are different tables and different types of uploaders.
I started with:
user.avatar = image.content
(where user and image are model instances, avatar and content are the carrierwave mounted uploaders) which worked sometimes. It seems to work all the time locally, with a file storage, but intermittent when using fog and s3.
In a mailing list post I found this code:
user.avatar = image.content.file
that again worked sometimes.
My working solution so far is:
require "open-uri"
begin
user.avatar = open(image.url)
rescue Errno::ENOENT => e
begin
user.avatar = open(image.path)
rescue Errno::ENOENT => e
# Ok, whatever.
end
end
which is not only ugly, but fails to pass the extension validation because the opening of a remote file doesn't maintain the extension (jpg, png, etc.).
Upvotes: 21
Views: 12099
Reputation: 19
You can do this by copying files.
store_path
is a carrierwave method from Uploader class. It returns uploaded file's folder relative path.
this clone file method should be called after model record is saved.
If record not saved, store_path
may return wrong path if you specify store_dir
with model id in uploader.
def clone_carrierwave_file(column_name)
origin_files = Dir[File.join(Rails.root, 'public', original_record.send(column_name).store_path, '*')]
return if origin_files.blank?
new_file_folder = File.join(Rails.root, 'public', send(column_name).store_path)
FileUtils.mkdir new_file_folder if !Dir.exist? new_file_folder
FileUtils.cp(origin_files, new_file_folder)
end
Hope it works.
Upvotes: 1
Reputation: 12356
I needed to copy a reference from one model to another model and I was successfully able to do so by doing the following:
my_new_model.update_column('attachment', my_other_model.attributes["attachment"]);
In this scenario, I did not care to actually make a copy of the file, nor did I care that 2 records were now linked to the same file (my system never deletes or modifies files after uploaded).
This may be useful to anyone who wants to just copy the reference to a file from one model to another model using the same uploader.
Upvotes: 1
Reputation: 14147
I just wanted to copy an avatar reference from one object to another, and what worked for me was:
objectB.avatar.retrieve_from_store!(objectA.avatar.identifier)
objectB.save
Upvotes: 0
Reputation: 6006
Perhaps one way you can do it is to set a remote image URL as per the Carrierwave gem documentation?
user.remote_avatar_url = image.url
Upvotes: 15
Reputation: 5741
Here's a (albeit hacky) solution to that doesn't require an HTTP request to fetch the image:
module UploadCopier
def self.copy(old, new)
new.instance_variable_set('@_mounters', nil)
old.class.uploaders.each do |column, uploader|
new.send("#{column}=", old.send(column))
end
end
end
old_user = User.last
new_user = User.new
UploadCopier.copy(old_user, new_user)
new_user.save
Upvotes: 1
Reputation: 14237
From solutions discussed here I created simple CopyCarrierwaveFile gem to do this
usage is something like this:
original_resource = User.last
new_resource = User.new
CopyCarrierwaveFile::CopyFileService.new(original_resource, new_resource, :avatar).set_file
new_resource.save
nev_resource.avatar.url # https://...image.jpg
Upvotes: 9