Download Endpoint
The download_endpoint
plugin provides a Rack app for
downloading uploaded files from specified storages. This can be useful when
files from your storage isn't accessible over URL (e.g. database storages) or
if you want to authenticate your downloads.
Global Endpoint
You can configure the plugin with the path prefix which the endpoint will be mounted on.
Shrine.plugin :download_endpoint, prefix: "attachments"
The plugin adds a Shrine.download_endpoint
method which returns a Rack
application that handles downloads using the rack_response
plugin. You can
run this Rack app inside your app on the prefix that you specified:
# config/routes.rb (Rails)
Rails.application.routes.draw do
# ...
mount Shrine.download_endpoint => "/attachments"
end
Links to the download endpoint are generated by calling
UploadedFile#download_url
instead of the usual UploadedFile#url
.
uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."
Endpoint via Uploader
You can also configure the plugin in the uploader directly - just make sure to mount it via your Uploader-class.
class ImageUploader < Shrine
plugin :download_endpoint, prefix: "images"
end
# config/routes.rb (Rails)
Rails.application.routes.draw do
# ...
mount ImageUploader.download_endpoint => "/images"
end
Hint: For shrine versions 2.x -> ensure that you don't include the plugin twice (globally and in your uploader class - see #408)
Calling from a controller
If you want to run additional code around the download (such as authentication),
mounting the download endpoint in your router might be limiting. You can instead
create a custom controller action and handle download requests there using
Shrine.download_response
:
# config/routes.rb (Rails)
Rails.application.routes.draw do
# ...
get "/attachments/*rest", to: "downloads#image"
end
# app/controllers/downloads_controller.rb (Rails)
class DownloadsController < ApplicationController
def image
# ... we can perform authentication here ...
set_rack_response ImageUploader.download_response(request.env)
end
private
def set_rack_response((status, headers, body))
self.status = status
self.headers.merge!(headers)
self.response_body = body
end
end
If you want to create an endpoint with a custom path, you can use the
rack_response
plugin directly, which this plugin uses
internally.
Host
You can specify download URL host via the :host
plugin option:
plugin :download_endpoint, host: "http://example.com"
or by passing :host
to UploadedFile#download_url
:
uploaded_file.download_url(host: "http://example.com")
#=> "http//example.com/attachments/eyJpZCI6ImFkdzlyeTM..."
Download options
If you want to pass additional options to Storage#open
, you can do so via
:download_options
:
plugin :download_endpoint, download_options: {
sse_customer_algorithm: "AES256",
sse_customer_key: "secret_key",
sse_customer_key_md5: "secret_key_md5",
}
You can also specify a proc to generate download options dynamically:
plugin :download_endpoint, download_options: -> (uploaded_file, request) {
{
sse_customer_algorithm: "AES256",
sse_customer_key: "secret_key",
sse_customer_key_md5: "secret_key_md5",
}
}
Performance considerations
Streaming files through the app might impact the request throughput, depending
on the web server you're using. So it's recommended to use a CDN, which can be
set via the :host
option.
Alternatively, you can have the endpoint redirect to the direct file URL:
plugin :download_endpoint, redirect: true
You can also specify a proc to generate your own redirect URL:
plugin :download_endpoint, redirect: -> (uploaded_file, request) do
uploaded_file.url(public: true)
end
Ad-hoc options
You can override any of the options above when creating the endpoint:
Shrine.download_endpoint(disposition: "attachment")
Plugin options
Name | Description | Default |
---|---|---|
:disposition | Whether browser should render the file inline or download it as an attachment | inline |
:download_options | Hash of storage-specific options passed to Storage#open | {} |
:host | URL host that will be added to download URLs | nil |
:prefix | Path prefix prepended to download URLs | nil |
:redirect | Whether to redirect to uploaded files on the storage | false |