Fallback Storage
The fallback_storage plugin allows you to specify a secondary (fallback) storage that
Shrine will read from if a file is not found in the primary storage.
This is especially useful when setting up a staging or development environment where you want to read files from production storage without replicating or copying large amounts of data locally.
Shrine.storages = {
cache: Shrine::Storage::S3.new(endpoint: "https://stage.example.com", prefix: "cache"),
store: Shrine::Storage::S3.new(endpoint: "https://stage.example.com"),
fallback: Shrine::Storage::S3.new(endpoint: "https://production.example.com"),
}
Shrine.plugin :fallback_storageBy default, the plugin looks for a storage named :fallback. You can override the fallback storage
name by passing the :store option:
Shrine.plugin :fallback_storage, store: :production_storeHow It Works
The plugin intercepts file existence checks, URL generation, and file reading methods on
Shrine::UploadedFile.
When performing read or check operations, Shrine will first attempt to query the main storage. If the file is missing in the primary storage, it seamlessly falls back to the configured fallback storage:
UploadedFile#exists?— Returns true if the file exists in the primary storage OR in the fallback storage.UploadedFile#url— Returns the URL from the primary storage if the file exists there, otherwise generates the URL using the fallback storage.UploadedFile#open(and methods relying on it likeread,download, etc.) — Opens the file from the primary storage if present, otherwise opens it from the fallback storage.
Write and Delete Operations
The plugin only affects read operations. Uploads, replacements, and deletions interact strictly with the primary storage:
- Uploads:
Shrine.uploadwrites files only to the main storage. - Deletes:
UploadedFile#deleteremoves the file only from the primary storage. The fallback storage remains untouched.
# File exists only in fallback storage
file = Shrine.uploaded_file({ "id" => "some-id", "storage" => "store" })
file.exists? # => true (found in fallback)
# Deleting removes it from primary storage, but fallback remains intact
file.delete
file.exists? # => true (still found in fallback)For additional security and reliability when pointing to a production environment, it is recommended to configure the credentials for the fallback storage (e.g., S3 access keys) with read-only permissions.
Rails example
A common use case is a staging environment that should have access to production files without storing its own copies. You can configure Shrine differently per environment:
# config/initializers/shrine.rb
if Rails.env.production?
Shrine.storages = {
cache: Shrine::Storage::S3.new(endpoint: "https://production.example.com", prefix: "cache"),
store: Shrine::Storage::S3.new(endpoint: "https://production.example.com"),
}
else
Shrine.storages = {
cache: Shrine::Storage::S3.new(endpoint: "https://stage.example.com", prefix: "cache"),
store: Shrine::Storage::S3.new(endpoint: "https://stage.example.com"),
production: Shrine::Storage::S3.new(endpoint: "https://production.example.com"),
}
Shrine.plugin :fallback_storage, store: :production
endWith this setup, staging uploads go to the staging endpoint, but any read for a missing file will automatically look in the production endpoint.