ruby-on-railsamazon-web-servicesamazon-s3rubygemsshrine

Shrine gem - how to prevent deletion of uploaded files from S3


I'm using shrine gem for storing images in S3 by Ruby on Rails.

How can I make shrine behave as follows?

1. When uploading files from Frontend, they are stored in S3.
2. When deleting files from Frontend, they are deleted from Database, "but not deleted from S3"

That is, once I upload images in S3, they never be deleted by users' actions.

I found similar question, but what I want to realize is quite the opposite condition.


The present condition is like this.

I mounded shrine to ImageUploader in accordance with shrine S3 docs.

When uploading file, they are stored in S3. And when I try to delete files from Database, they are also deleted from S3.


This is the code block which uploads files to S3 and deletes from S3.

config/initializers/shrine.rb

require "shrine"
require "shrine/storage/file_system"
require "shrine/storage/s3"


s3_options = {
    access_key_id: ENV[ACCESS_KEY_ID],
    secret_access_key: ENV[SECRET_ACCESS_KEY],
    region: ENV[REGION],
    bucket: ENV[BUCKET],
}

Shrine.storages = {
    cache: Shrine::Storage::S3.new(prefix: ..., **s3_options),
    store: Shrine::Storage::S3.new(prefix: ..., **s3_options),
}


Shrine.plugin :activerecord           
Shrine.plugin :cached_attachment_data 
Shrine.plugin :restore_cached_data 

Shrine.plugin :url_options,
              cache: { public: true, host: ENV[CLOUDFRONT_URL] },
              store: { public: true, host: ENV[CLOUDFRONT_URL] }

On ImageUploader < Shrine, set resize logics. And on Photo model, mount the uploader like include ImageUploader::Attachment(:image)

When deleting files from Database, I used ActiveRecord like this.(on this point, they are also deleted from S3)

class PhotoController < ApiController

def destroy
  photo = Photo.find(params[:id])
  photo.destroy!

  render json: photo, serializer: PhotoSerializer
end

Solution

  • There are two ways you can achieve what you want.

    Method 1: Skip ActiveRecord callbacks that trigger Shrine's callbacks by using delete instead of destroy on your controller.

    Method 2: Add mirroring and backup to your Shrine configuration like so

     Shrine.storages = { cache: ..., store: ..., backup: ... }
    
     Shrine.plugin :mirroring, mirror: { store: :backup }