V1.3: MIME Types


A view can handle several MIME Types. Before diving into this subject, please consider to read how actions handle MIME Types.

It’s important to highlight the correlation between the format and template name. For a given MIME Type, Rack (and then Hanami) associate a format for it. XML is mapped from application/xml to :xml, HTML is text/html and becomes :html for us.

Format MUST be the first extension of the template file name. Eg dashboard/index.html.*.

Default Rendering

If our action (Web::Controllers::Dashboard::Index) is handling a JSON request, and we have defined a template for it (apps/web/templates/dashboard/index.json.erb), our view will use it for rendering.

# apps/web/templates/dashboard/index.json.erb
{"foo":"bar"}
% curl -H "Accept: application/json" http://localhost:2300/dashboard
{"foo":"bar"}

We’re still able to request HTML format.

# apps/web/templates/dashboard/index.html.erb
<h1>Dashboard</h1>
% curl -H "Accept: text/html" http://localhost:2300/dashboard
<h1>Dashboard</h1>

In case we request an unsupported MIME Type, our application will raise an error.

% curl -H "Accept: application/xml" http://localhost:2300/dashboard
Hanami::View::MissingTemplateError: Can't find template "dashboard/index" for "xml" format.

View For Specific Format

This scenario works well if the presentational logic of a view can be applied for all the format templates that it handles. What if we want to have a custom rendering or different presentational logic?

We can inherit from our view and declare that our subclass only handles a specific format.

# apps/web/views/dashboard/json_index.rb
require_relative './index'

module Web
  module Views
    module Dashboard
      class JsonIndex < Index
        format :json

        def render
          raw JSON.generate({foo: 'bar'})
        end
      end
    end
  end
end

JSON requests for /dashboard, will be handled by our JsonIndex.

There is NO convention between the handled format and the class name. The important part is format :json.

With the example above we took advantage of custom rendering to not use the template and let our serializer to return JSON for us.