How can I reorganize an existing folder hierarchy using CarrierWave?

I am trying to move files around my S3 container using CarrierWave to reorganize the folder structure.

I came to an existing Rails application where all the images for the class are uploaded to a folder named /uploads . This causes problems when, if two users upload different images with the same name, the second image overwrites the first. To solve this problem, I want to reorganize the folders to place each image in its own directory according to the instance of the ActiveRecord object. We use CarrierWave to control file downloads.

The old bootloader code had the following method:

 def store_dir "uploads" end 

I changed the method to reflect my new file storage scheme:

 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end 

This works great for new images, but breaks the URL for old images. Existing images report that their URL is inside the new folder immediately after changing the model, and the image files are still stored in /uploads .

 > object.logo.store_dir => "uploads/object/logo/133" 

This is not true. This object should report its logo to /uploads .

My solution is to write a script to move the image files, but I did not find the correct methods in CarrierWave to move the files. My script will look something like this:

 MyClass.all.each |image| filename = file.name #This method exists in my uploader, returns the file name #Move the file from "/uploads" to "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end 

What should I do in the third line of my script to move the file to a new location?

+8
source share
1 answer

A WARNING. This is not tested, so please do not use it in production before testing it.

Here, when you change the contents of "store_dir", all your old downloads will be missing. You already know that. Interaction with S3 directly seems to be the most obvious way to resolve this issue, since the carrier wave does not have a moving function.

One thing that could work would be to re-download your downloads and change the store_dir path in the before: store callback.

In your bootloader:

 #Use the old uploads directory so carriewave knows where the original upload is def store_dir 'uploads' end before :store, :swap_out_store_dir def swap_out_store_dir self.class_eval do def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end end end 

And then run the script as follows:

 MyClass.all.each do |image| image.image.cache! #create a local cache so that store! has something to store image.image.store! end 

After that, make sure that the files are copied to the right places. Then you will have to delete the old files to download. Also, delete the one-time code of the code downloaded above and replace it with the new store_dir path:

 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id} " end 

I have not tested this, so I can not guarantee that it will work. First use the test data to find out if it works and comments here if you have had any success.

+15
source

All Articles