How to update/rename a carrierwave uploaded file?
Asked Answered
C

6

5

I cant figure out how to update/rename a file uploaded/managed with Carrierwave-mongoid in rails 3.2.6. I want to rename the file in the db as well as on the filesystem.

Something like this maybe...

def rename( id , new_name )
  f = UploadedFile.find(id)

  if f.update_attributes({ f.file.original_filename: new_name })  # this is WRONG, what is right???
    new_path = File.join( File.dirname( f.file.current_path ) , new_name ))
    FileUtils.mv( f.file.current_path , new_path )
  end

  return f
end

Let me add this is after it has been uploaded already.

Cata answered 18/10, 2012 at 21:44 Comment(0)
C
5

I was able to get the following working, although I'm sure there is a more elegant way. I'd appreciate any comments on the following

*add this to app/uploaders/file_uploader.rb

def rename(new_name)
  sf = model.file.file
  new_path = File.join( File.dirname( sf.file ) , "#{new_name}#{File.extname( sf.file )}")
  new_sf = CarrierWave::SanitizedFile.new sf.move_to(new_path)
  model.file.cache!(new_sf)
  model.save!
  return model
end

Thanks!

Cata answered 19/10, 2012 at 20:13 Comment(2)
duh! This is actually storing the file twice, once from cache! and once from move_to.Cata
I needed to convert the format of previously uploaded files to .jpg, and then get carrierwave to see them as the uploaded file. Your code here put be on the right path with SanitizedFile.new which I called on the converted/renamed file to get it associated my model. I discovered that I needed to call recreate_versions! after saving the model to get the versions generated properly.Lattimer
B
2

The most efficient way to do this is to just move the existing S3 object (assuming your storage layer is S3):

def rename(new_name)
  bucket_name = "yourapp-#{Rails.env}"
  resource = Aws::S3::Resource.new
  bucket = resource.bucket(bucket_name)
  object = bucket.object(path)
  new_filename = "#{new_name}#{File.extname(path)}"
  new_path = File.join(File.dirname(path), new_filename)
  object.move_to(bucket: bucket_name, key: new_path)

  model.update_column(mounted_as, new_filename)
  model.reload

  # Now call `recreate_versions!(*versions.keys)`
  # if you want versions updated. Explicitly passing
  # versions will prevent the base version getting
  # reuploaded.

  model
end

This is using the aws-sdk-s3 gem.

Boondocks answered 17/10, 2018 at 15:21 Comment(0)
H
1

I store image files -- and derivative versions -- in an S3-compatible solution. I use Carrierwave (1.2.2) with the "fog-aws" gem (3.0.0) on Rails 5.1. The following public method works for me when added to the "uploader" file (eg, app/uploaders/example_uploader.rb):

class ExampleUploader < CarrierWave::Uploader::Base
  <snip>

  # Renames original file and versions to match given filename
  #
  # Options:
  # * +:keep_original+ - Do not remove original file and versions (ie, copy only)
  def rename(new_filename, options = {})
    return if !file || new_filename == file.filename
    target = File.join(store_path, new_filename)
    file.copy_to(target)
    versions.keys.each do |k|
      target = File.join(store_path, "#{k}_#{new_filename}")
      version = send(k).file
      version.copy_to(target)
    end
    remove! unless options[:keep_original]
    model.update_column(mounted_as, new_filename) && model.reload
  end

  <snip>
end
Heilbronn answered 31/8, 2019 at 18:2 Comment(0)
M
0

I used this rake task for reprocessing uploaded images after modifying version settings (filename and image size) in my uploader file:

# Usage: rake carrierwave:reprocess class=Model
namespace :carrierwave do
  task :reprocess => :environment do

    CLASS = ENV['class'].capitalize
    MODEL = Kernel.const_get(CLASS)
    records = MODEL.all

    records.each do |record|
      record.photo.recreate_versions! if record.photo?
    end

  end
end

Notes:

  • Replace "photo" with whatever you named your uploader.
  • Rake tasks go in the lib/tasks folder.
  • This is using Active Record, not sure if Mongoid needs something different.
Magnificence answered 19/10, 2012 at 1:41 Comment(2)
Thanks, i was able to get the below answer working, let me know what you think, appreciate it.Cata
Works on mongoid too.Malamute
S
0

Based on @user892583, I worked on it and came up with a simpler solution:

def rename!(new_name)
  new_path = File.join(File.dirname(file.file), new_name)
  file.move_to(new_path)
end
Swill answered 22/6, 2014 at 20:53 Comment(0)
T
0

I did this with this way:

  def filename
    if !cached? && file.present?
      new_filename = 'foobar'
      new_path = File.join(File.dirname(file.path), new_filename)
      file.move_to(new_path)
      recreate_versions!
      new_filename
    else
      super
    end
  end

I think this is only right way to rename file.

Toehold answered 5/1, 2018 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.