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.

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

We’re still able to request HTML format.

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

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

  1. % curl -H "Accept: application/xml" http://localhost:2300/dashboard
  2. 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.

  1. # apps/web/views/dashboard/json_index.rb
  2. require_relative './index'
  3. module Web
  4. module Views
  5. module Dashboard
  6. class JsonIndex < Index
  7. format :json
  8. def render
  9. raw JSON.generate({foo: 'bar'})
  10. end
  11. end
  12. end
  13. end
  14. 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.