It’s surprisingly hard to find info on getting the MIME type of a file in Rails. Rails has MIME::Type (and the confusing and undocumented MIME::Types). You can call Mime::Type.lookup on a filename or Mime::Type.lookup_by_extension on an extension (without a leading .) but a lot of common types aren’t registered by default. You can enable additional types in config/initializers/mime_types.rb but that’s really for configuring what respond_to knows about. I want to be able to get the MIME type of a random upload so I can handle it properly. Having to manually define types defeats the purpose.

So, here’s the quick and dirty way. Under the hood, Rails uses Rack::Mime and Rack::Mime.mime_type takes a file extension (with the leading .!!!) and returns the MIME type for a much wider range of files. Grab the extension with File.extname and put to together like this:

1
mime_type = Rack::Mime.mime_type(File.extname(filename))

Then throw it in a case statement:

1
2
3
4
5
6
7
8
9
10
11
mime_type = Rack::Mime.mime_type(File.extname(filename))
case mime_type
when /^image/
  # Something
when /^video/
  # Something
when /^audio/
  # Something
else
  # Handle the unknown
end

Just don’t for get the else statement to handle any unrecognized types.

I use this in two ways:

First, to validate the an upload is of a type I want. You can use accept= on your HTML file input field, however you’re trusting the browser to enforce your restrictions. Your app should do so as well.

Second, in cases where the user is allowed to upload more than one type of thing, say an image or a video, to set the appropriate display code (image_tag vs video_tag).

One last trick, straight from the [Rack::Mime docs]http://www.rubydoc.info/github/rack/rack/Rack/Mime). If you need even more types, you can pull in the system mime.types file:

1
2
3
4
require 'webrick/httputils'
mime_types = '/etc/mime.types' # '/etc/apache2/mime.types' on OS/X
list = WEBrick::HTTPUtils.load_mime_types(mime_types)
Rack::Mime::MIME*TYPES.merge!(list)

On OS/X this takes you from ~600 know types to ~1600, most of which I’ve never heard of. Now you’re truly covered.

Comments