module Shrine::Plugins::UploadEndpoint

  1. lib/shrine/plugins/upload_endpoint.rb

The upload_endpoint plugin provides a Rack endpoint which accepts file uploads and forwards them to specified storage. It can be used with client-side file upload libraries like FineUploader, Dropzone or jQuery-File-Upload for asynchronous uploads.

plugin :upload_endpoint

The plugin adds a Shrine.upload_endpoint method which, given a storage identifier, returns a Rack application that accepts multipart POST requests, and uploads received files to the specified storage. You can run this Rack application inside your app:

# config.ru (Rack)
map "/images/upload" do
  run ImageUploader.upload_endpoint(:cache)
end

# OR

# config/routes.rb (Rails)
Rails.application.routes.draw do
  mount ImageUploader.upload_endpoint(:cache) => "/images/upload"
end

Asynchronous upload is typically meant to replace the caching phase in the default synchronous workflow, so we want the uploads to go to temporary (:cache) storage.

The above will create a POST /images/upload endpoint, which uploads the file received in the file param using ImageUploader, and returns a JSON representation of the uploaded file.

# POST /images/upload
{
  "id": "43kewit94.jpg",
  "storage": "cache",
  "metadata": {
    "size": 384393,
    "filename": "nature.jpg",
    "mime_type": "image/jpeg"
  }
}

This JSON string can now be assigned to an attachment attribute instead of a raw file. In a form it can be written to a hidden attachment field, and then it can be assigned as the attachment.

Limiting filesize

It's good practice to limit the accepted filesize of uploaded files. You can do that with the :max_size option:

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

If the uploaded file is larger than the specified value, a 413 Payload Too Large response will be returned.

Context

The upload context will not contain :record and :name values, as the upload happens independently of a database record. The endpoint will sent the following upload context:

  • :action - holds the value :upload

  • :request - holds an instance of Rack::Request

You can update the upload context via :upload_context:

plugin :upload_endpoint, upload_context: -> (request) do
  { location: "my-location" }
end

Upload

You can also customize the upload itself via the :upload option:

plugin :upload_endpoint, upload: -> (io, context, request) do
  # perform uploading and return the Shrine::UploadedFile
end

Response

The response returned by the endpoint can be customized via the :rack_response option:

plugin :upload_endpoint, rack_response: -> (uploaded_file, request) do
  body = { data: uploaded_file.data, url: uploaded_file.url }.to_json
  [201, { "Content-Type" => "application/json" }, [body]]
end

Ad-hoc options

You can override any of the options above when creating the endpoint:

Shrine.upload_endpoint(:cache, max_size: 20*1024*1024)

Methods

Public Class

  1. configure
  2. load_dependencies

Public Class methods

configure (uploader, opts = {})
[show source]
# File lib/shrine/plugins/upload_endpoint.rb, line 111
def self.configure(uploader, opts = {})
  uploader.opts[:upload_endpoint_max_size] = opts.fetch(:max_size, uploader.opts[:upload_endpoint_max_size])
  uploader.opts[:upload_endpoint_upload_context] = opts.fetch(:upload_context, uploader.opts[:upload_endpoint_upload_context])
  uploader.opts[:upload_endpoint_upload] = opts.fetch(:upload, uploader.opts[:upload_endpoint_upload])
  uploader.opts[:upload_endpoint_rack_response] = opts.fetch(:rack_response, uploader.opts[:upload_endpoint_rack_response])
end
load_dependencies (uploader, opts = {})
[show source]
# File lib/shrine/plugins/upload_endpoint.rb, line 107
def self.load_dependencies(uploader, opts = {})
  uploader.plugin :rack_file
end