Determine MIME Type
The determine_mime_type
plugin allows you to determine
and store the actual MIME type of the file analyzed from file content.
plugin :determine_mime_type
By default the UNIX file utility is used to determine the MIME type, and the
result is automatically written to the mime_type
metadata field. You can
choose a different built-in MIME type analyzer, for example:
plugin :determine_mime_type, analyzer: :marcel
Analyzers
The following analyzers are accepted:
Name | Description |
---|---|
:file | (Default). Uses the file utility to determine the MIME type from file contents. It is installed by default on most operating systems, but the Windows equivalent needs to be installed separately. |
:fastimage | Uses the fastimage gem to determine the MIME type from file contents. Fastimage is optimized for speed over accuracy. Best used for image content. |
:filemagic | Uses the ruby-filemagic gem to determine the MIME type from file contents, using a similar MIME database as the file utility. Unlike the file utility, ruby-filemagic works on Windows without any setup. |
:mimemagic | Uses the mimemagic gem to determine the MIME type from file contents. Unlike ruby-filemagic, mimemagic is a pure-ruby solution, so it will work across all Ruby implementations. |
:marcel | Uses the marcel gem to determine the MIME type from file contents. Marcel is Basecamp's wrapper around mimemagic, it adds priority logic (preferring magic over name when given both), some extra type definitions, and common type subclasses (including Keynote, Pages, etc). |
:mime_types | Uses the mime-types gem to determine the MIME type from the file extension. Note that unlike other solutions, this analyzer is not guaranteed to return the actual MIME type of the file. |
:mini_mime | Uses the mini_mime gem to determine the MIME type from the file extension. Note that unlike other solutions, this analyzer is not guaranteed to return the actual MIME type of the file. |
:content_type | Retrieves the value of the #content_type attribute of the IO object. Note that this value normally comes from the "Content-Type" request header, so it's not guaranteed to hold the actual MIME type of the file. |
You'll need to ensure the file utility or gem is in installed on your system for Shrine to use the analyzer.
Analyzer Options
Currently, Marcel is the only analyzer that accepts options to be passed in. Analyzer options can be set in one of two ways:
plugin :determine_mime_type, analyzer: :marcel, analyzer_options: { filename_fallback: true }
# or
plugin :determine_mime_type, analyzer: -> (io, analyzers) do
mime_type = analyzers[:marcel].call(io, filename_fallback: true)
end
The :filename_fallback
option for Marcel analyzer lets it use the filename as
a fallback option when it fails to determine the MIME type from the file
content. Set :filename_fallback
to true
in order to fallback to using the
filename or set to false
to not use the filename (this is the default).
Issues
If you find using a single analyzer is not able to recognize all of the file
types in your application, you can build your own custom analyzer and combine
the built-in analyzers. For example, if you want to correctly determine MIME
type of .css, .js, .json, .csv, .xml, or similar text-based files, you can
combine file
and mime_types
analyzers:
plugin :determine_mime_type, analyzer: -> (io, analyzers) do
mime_type = analyzers[:file].call(io)
mime_type = analyzers[:mime_types].call(io) if mime_type == "text/plain"
mime_type
end
API
You can also use the methods for determining the MIME type directly:
# or YourUploader.determine_mime_type(io)
Shrine.determine_mime_type(io) #=> "image/jpeg" (calls the defined analyzer)
# or just
Shrine.mime_type(io) #=> "image/jpeg" (calls the defined analyzer)
# or YourUploader.mime_type_analyzers
Shrine.mime_type_analyzers[:file].call(io) #=> "image/jpeg" (calls a built-in analyzer)
Instrumentation
If the instrumentation
plugin has been loaded, the determine_mime_type
plugin
adds instrumentation around MIME type analyzation.
# instrumentation plugin needs to be loaded *before* determine_mime_type
plugin :instrumentation
plugin :determine_mime_type
Analyzing MIME type will trigger a mime_type.shrine
event with the following
payload:
Key | Description |
---|---|
:io | The IO object |
:uploader | The uploader class that sent the event |
A default log subscriber is added as well which logs these events:
MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
You can also use your own log subscriber:
plugin :determine_mime_type, log_subscriber: -> (event) {
Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
}
{"name":"mime_type","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
Or disable logging altogether:
plugin :determine_mime_type, log_subscriber: nil