module Shrine::Plugins::RemoteUrl

  1. lib/shrine/plugins/remote_url.rb

The remote_url plugin allows you to attach files from a remote location.

plugin :remote_url, max_size: 20*1024*1024

If for example your attachment is called “avatar”, this plugin will add #avatar_remote_url and #avatar_remote_url= methods to your model.

user.avatar #=> nil
user.avatar_remote_url = "http://example.com/cool-image.png"
user.avatar #=> #<Shrine::UploadedFile>

user.avatar.mime_type         #=> "image/png"
user.avatar.size              #=> 43423
user.avatar.original_filename #=> "cool-image.png"

You can also use #remote_url= and #remote_url methods directly on the Shrine::Attacher:

attacher.remote_url = "http://example.com/cool-image.png"

The file will by default be downloaded using Down, which is a wrapper around the open-uri standard library. Note that Down expects the given URL to be URI-encoded.

Maximum size

It's a good practice to limit the maximum filesize of the remote file:

plugin :remote_url, max_size: 20*1024*1024 # 20 MB

Now if a file that is bigger than 20MB is assigned, download will be terminated as soon as it gets the “Content-Length” header, or the size of currently downloaded content surpasses the maximum size. However, if for whatever reason you don't want to limit the maximum file size, you can set :max_size to nil:

plugin :remote_url, max_size: nil

Custom downloader

If you want to customize how the file is downloaded, you can override the :downloader parameter and provide your own implementation. For example, you can ensure the URL is URI-encoded (using the Addressable gem) before passing it to Down:

require "down"
require "addressable/uri"

plugin :remote_url, max_size: 20*1024*1024, downloader: ->(url, max_size:) do
  url = Addressable::URI.encode(Addressable::URI.decode(url))
  Down.download(url, max_size: max_size, max_redirects: 4, read_timeout: 3)
end

Errors

If download errors, the error is rescued and a validation error is added equal to the error message. You can change the default error message:

plugin :remote_url, error_message: "download failed"
plugin :remote_url, error_message: ->(url, error) { I18n.t("errors.download_failed") }

Background

If you want the file to be downloaded from the URL in the background, you can use the shrine-url storage which allows you to assign a custom URL as cached file ID, and pair that with the backgrounding plugin.

Methods

Public Class

  1. configure

Public Class methods

configure (uploader, opts = {})
[show source]
# File lib/shrine/plugins/remote_url.rb, line 74
def self.configure(uploader, opts = {})
  raise Error, "The :max_size option is required for remote_url plugin" if !opts.key?(:max_size) && !uploader.opts.key?(:remote_url_max_size)

  uploader.opts[:remote_url_downloader] = opts.fetch(:downloader, uploader.opts.fetch(:remote_url_downloader, :open_uri))
  uploader.opts[:remote_url_max_size] = opts.fetch(:max_size, uploader.opts[:remote_url_max_size])
  uploader.opts[:remote_url_error_message] = opts.fetch(:error_message, uploader.opts[:remote_url_error_message])
end