Rails – Carrierwave: Remove avatar and multiple files from S3
When a User destroys a record, what’s the point of keeping the uploaded files/images with Carrierwave on S3?
It’s wasted storage space. You need to be able to remove images and files from your Model.
In this tutorial, we will see how to use the Carrierwave method :remove_avatar
to delete a file uploaded on S3 from your Rails app. We will also fix the problem of leftover empty directories.
1. Delete avatar and multiple Carrierwave files from S3 on Model destroy
Carrierwave provides a convenient method for removing uploaded files if a checkbox is checked. We will use and adapt it to delete file from S3 after the Model has been destroyed.
class User < ActiveRecord::Base mount_uploader :avatar, AvatarUploader before_destroy :clean_s3 private def clean_s3 avatar.remove! avatar.thumb.remove! # if you have thumb version or any other version rescue Excon::Errors::Error => error puts "Something gone wrong" false end end
This code comes from this nice StackOverflow answer.
To be complete, let’s say your model stores several files like Word documents and PDF, and not images avatar like the example on the docs, and you have the line mount_uploaders :attachments, AttachmentUploader
in your model.
You’ll want to iterate through each attachment to remove it one at a time. Here is how:
def clean_s3 attachments.each(&:remove!) rescue Excon::Errors::Error => error puts "Couldn't be removed" false end
2. Delete empty directories
After implementing step 1 of this Carrierwave tutorial and destroying the object, you’ll notice that empty directories remain in the tmp cache directory.
While unpleasant, it’s not really a problem unless you have a very large amount of them.
But to keep things tidy, let’s see how to remove them. We will implement this a simple version of this solution from the wiki.
Your AttachmentUploader will look like this:
class AttachmentUploader < CarrierWave::Uploader::Base after :remove, :delete_empty_upstream_dirs # Clean up empty directories when the files in them are deleted # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end def delete_empty_upstream_dirs path = ::File.expand_path(store_dir, root) Dir.delete(path) # fails if path not empty dir, beware ".DS_Store" when in development rescue SystemCallError true # nothing, the dir is not empty end end