Skip to main content

Data URI

The data_uri plugin enables you to upload files as data URIs. This plugin is useful for example when using HTML5 Canvas.

plugin :data_uri

Usage

The plugin will add the #<name>_data_uri writer to your model, which parses the given data URI string and uploads it to temporary storage:

photo.image_data_uri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"
photo.image.mime_type #=> "image/png"
photo.image.size      #=> 43423

If you're using Shrine::Attacher directly, you can use Attacher#assign_data_uri:

attacher.assign_data_uri("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA")
attacher.file.mime_type #=> "image/png"
attacher.file.size      #=> 43423

Errors

If the data URI wasn't correctly parsed, an error message will be added to the attachment column. You can change the default error message:

plugin :data_uri, error_message: "data URI was invalid"
plugin :data_uri, error_message: ->(uri) { I18n.t("errors.data_uri_invalid") }

Uploader options

Any options passed to Attacher#assign_data_uri will be forwarded to Attacher#assign (and Shrine#upload):

attacher.assign_data_uri(uri, metadata: { "filename" => "nature.jpg" })

File extension

A data URI doesn't convey any information about the file extension, so when attaching from a data URI, the uploaded file location will be missing an extension. If you want the upload location to always have an extension, you can load the infer_extension plugin to infer it from the MIME type.

plugin :infer_extension

Parsing data URI

If you just want to parse the data URI and create an IO object from it, you can do that with Shrine.data_uri. If the data URI cannot be parsed, a Shrine::Plugins::DataUri::ParseError will be raised.

# or YourUploader.data_uri(...)
io = Shrine.data_uri("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA")
io.content_type #=> "image/png"
io.size         #=> 21
io.read         # decoded content

When the content type is ommited, text/plain is assumed. The parser also supports raw data URIs which aren't base64-encoded.

# or YourUploader.data_uri("...")
io = Shrine.data_uri("data:,raw%20content")
io.content_type #=> "text/plain"
io.size         #=> 11
io.read         #=> "raw content"

You can also assign a filename:

io = Shrine.data_uri("data:,content", filename: "foo.txt")
io.original_filename #=> "foo.txt"

Generating data URI

This plugin also adds UploadedFile#data_uri method, which returns a base64-encoded data URI of the file content, and UploadedFile#base64, which simply returns the file content base64-encoded.

uploaded_file.data_uri #=> "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"
uploaded_file.base64   #=> "iVBORw0KGgoAAAANSUhEUgAAAAUA"

Instrumentation

If the instrumentation plugin has been loaded, the data_uri plugin adds instrumentation around data URI parsing.

# instrumentation plugin needs to be loaded *before* data_uri
plugin :instrumentation
plugin :data_uri

Parsing data URIs will trigger a data_uri.shrine event with the following payload:

KeyDescription
:data_uriThe data URI string
:uploaderThe uploader class that sent the event

A default log subscriber is added as well which logs these events:

Data URI (5ms) – {:uploader=>Shrine}

You can also use your own log subscriber:

plugin :data_uri, log_subscriber: -> (event) {
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, uploader: event[:uploader])
}
{"name":"data_uri","duration":5,"uploader":"Shrine"}

Or disable logging altogether:

plugin :data_uri, log_subscriber: nil