Skip to main content

Mirroring

The mirroring plugin enables replicating uploads and deletes to other storages. This can be useful for setting up a backup storage, or when migrating files from one storage to another.

Shrine.plugin :mirroring, mirror: { store: :other_store }

With the above setup, any upload and delete to :store will be replicated to :other_store.

file = Shrine.upload(io, :store) # uploads to :store and :other_store
file.delete                      # deletes from :store and :other_store

You can skip mirroring for a specific upload/delete call by passing mirror: false:

file = Shrine.upload(io, :store, mirror: false) # skips mirroring
file.delete(mirror: false)                      # skips mirroring

Multiple storages

You can mirror to multiple storages by specifying an array:

Shrine.plugin :mirroring, mirror: {
  store: [:other_store_1, :other_store_2]
}

Backup storage

If you want the mirror storage to act as a backup, you can disable mirroring deletes:

Shrine.plugin :mirroring, mirror: { ... }, delete: false

Backgrounding

You can have mirroring performed in a background job:

Shrine.mirror_upload_block do |file, **options|
  MirrorUploadJob.perform_async(file.shrine_class.name, file.data)
end

Shrine.mirror_delete_block do |file|
  MirrorDeleteJob.perform_async(file.shrine_class.name, file.data)
end
class MirrorUploadJob
  include Sidekiq::Worker

  def perform(shrine_class, file_data)
    shrine_class = Object.const_get(shrine_class)

    file = shrine_class.uploaded_file(file_data)
    file.mirror_upload
  end
end
class MirrorDeleteJob
  include Sidekiq::Worker

  def perform(shrine_class, file_data)
    shrine_class = Object.const_get(shrine_class)

    file = shrine_class.uploaded_file(file_data)
    file.mirror_delete
  end
end

API

You can disable automatic mirroring and perform mirroring manually:

# disable automatic mirroring of uploads and deletes
Shrine.plugin :mirroring, mirror: { ... }, upload: false, delete: false

To perform mirroring, you can call UploadedFile#mirror_upload and UploadedFile#mirror_delete:

file = Shrine.upload(io, :store) # upload to :store
file.mirror_upload               # upload to :other_store

file.delete                      # delete from :store
file.mirror_delete               # delete from :other_store

If you've set up backgrounding, you can use UploadedFile#mirror_upload_background and UploadedFile#mirror_delete_background to call the background block instead:

file = Shrine.upload(io, :store) # upload to :store
file.mirror_upload_background    # spawn mirror upload background job

file.delete                      # delete from :store
file.mirror_delete_background    # spawn mirror delete background job