4
votes

I'm following this article in CarrierWave Wiki https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Add-more-files-and-remove-single-file-when-using-default-multiple-file-uploads-feature to implement adding more images and removing images for a model in my system using CarrierWave Multiple Uploads feature.

The main code in that article is

def add_more_images(new_images)
  images = @gallery.images 
  images += new_images
  @gallery.images = images
end

def remove_image_at_index(index)
  remain_images = @gallery.images # copy the array
  deleted_image = remain_images.delete_at(index) # delete the target image
  deleted_image.try(:remove!) # delete image from S3
  @gallery.images = remain_images # re-assign back
end

It works. However, it is too slooooow. I have looked at the log and the overall processing time is as follow:

  1. Upload 1 image: it takes 5000ms for example
  2. Add 1 more image: it takes 8500ms (2 images)
  3. Add 1 more image: it takes 12000ms (3 images)
  4. Remove 1 image: it takes 8400ms (back to 2 images)

I have tested the sample app of this solution written by the author on my local machine and it was very slow too.

It seems like CarrierWave reuploads and re-processes all images even we only add or remove 1 image. I think because we are re-assigning back new array of images to @gallery so that it treats old images as new ones.

Also there is a related issue here https://github.com/carrierwaveuploader/carrierwave/issues/1704#issuecomment-259106600

Does anyone have any better solution for adding and removing images using CarrierWave multiple upload feature?

Thanks.

1

1 Answers

0
votes

when you call model.images = remain_images, carrierwave will upload all images. So the more images you stored in a column, the longer it will take. See: mount.rb#L300, mounter.rb#L40

I had this problem before, the following is my code:

new_images = self.logo_images.clone
4.times do |t|
  next if !(image = params[:"logo_image#{t + 1}"])
  new_images[t] = image
  changed = true
end
self.logo_images = new_images if changed
...
self.save if changed

And this is the hack...

(works fine with carrierwave 1.0.0 and carrierwave-aws 1.1.0)

mounter = self.send(:_mounter, :logo_images)
4.times do |t|
  next if !(image = params[:"logo_image#{t + 1}"])
  uploader = mounter.blank_uploader
  uploader.cache!(image)
  mounter.uploaders[t] = uploader
  changed = true
end
mounter.uploaders.each{|s| s.send(:original_filename=, s.file.filename) if !s.filename} if changed 
...
self.save if changed