module Shrine::Plugins::DownloadEndpoint

  1. lib/shrine/plugins/download_endpoint.rb

The download_endpoint plugin provides a Rack endpoint 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. It requires the Roda gem.

# Gemfile
gem "roda" # dependency of the download_endpoint plugin

You can configure the plugin with the path prefix which the endpoint will be mounted on.

plugin :download_endpoint, prefix: "attachments"

The endpoint should then be mounted on the specified prefix:

# config.ru (Rack)
map "/attachments" do
  run Shrine.download_endpoint
end

# OR

# config/routes.rb (Rails)
Rails.application.routes.draw do
  mount Shrine.download_endpoint => "/attachments"
end

Any uploaded file can be downloaded through this endpoint. When a file is requested, its content will be efficiently streamed from the storage into the response body.

Links to the download endpoint are generated by calling UploadedFile#download_url instead of the usual UploadedFile#url.

uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."

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..."

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
# or
plugin :download_endpoint, redirect: -> (uploaded_file, request) do
  # return URL which the request will redirect to
end

Custom endpoint

If you want to have more control on download requests, you can use the rack_response plugin which this plugin uses internally.

Methods

Public Class

  1. configure
  2. load_dependencies

Public Class methods

configure (uploader, opts = {})

Accepts the following options:

:prefix

The location where the download endpoint was mounted. If it was mounted at the root level, this should be set to nil.

:host

The host that you want the download URLs to use (e.g. your app's domain name or a CDN). By default URLs are relative.

:disposition

Can be set to “attachment” if you want that the user is always prompted to download the file when visiting the download URL. The default is “inline”.

:redirect

If set to true, requests will redirect to the direct file URL. If set to a proc object, the proc will called with the UploadedFile instance and the Rack::Request object, and is expected to return the URL to which the request will redirect to. Defaults to false, meaning that the file content will be served through the endpoint.

[show source]
# File lib/shrine/plugins/download_endpoint.rb, line 101
def self.configure(uploader, opts = {})
  uploader.opts[:download_endpoint_storages] = opts.fetch(:storages, uploader.opts[:download_endpoint_storages])
  uploader.opts[:download_endpoint_prefix] = opts.fetch(:prefix, uploader.opts[:download_endpoint_prefix])
  uploader.opts[:download_endpoint_disposition] = opts.fetch(:disposition, uploader.opts.fetch(:download_endpoint_disposition, "inline"))
  uploader.opts[:download_endpoint_host] = opts.fetch(:host, uploader.opts[:download_endpoint_host])
  uploader.opts[:download_endpoint_redirect] = opts.fetch(:redirect, uploader.opts.fetch(:download_endpoint_redirect, false))

  Shrine.deprecation("The :storages download_endpoint option is deprecated, you should use UploadedFile#download_url for generating URLs to the download endpoint.") if uploader.opts[:download_endpoint_storages]

  uploader.assign_download_endpoint(App) unless uploader.const_defined?(:DownloadEndpoint)
end
load_dependencies (uploader, opts = {})
[show source]
# File lib/shrine/plugins/download_endpoint.rb, line 75
def self.load_dependencies(uploader, opts = {})
  uploader.plugin :rack_response
  uploader.plugin :_urlsafe_serialization
end