In the previous section we generated a view. Let’s use it.

Default Rendering

First, we edit the corresponding template:

  1. # apps/web/templates/dashboard/index.html.erb
  2. <h1>Dashboard</h1>

By visiting /dashboard, we should see <h1>Dashboard</h1> in our browser.

Again we should look at the naming convention. Our view is Web::Views::Dashboard::Index, while the file name of the template is web/templates/dashboard/index.

For a given view Web::Views::Dashboard::Index, the corresponding template MUST be available at apps/web/templates/dashboard/index.html.erb.

Context

While rendering a template, variable lookups requested by the template go to a view context.

  1. # apps/web/templates/dashboard/index.html.erb
  2. <h1><%= title %></h1>

If we amend our template by adding an interpolated variable, the view is responsible for providing it.

  1. # apps/web/views/dashboard/index.rb
  2. module Web
  3. module Views
  4. module Dashboard
  5. class Index
  6. include Web::View
  7. def title
  8. 'Dashboard'
  9. end
  10. end
  11. end
  12. end
  13. end

The view now responds to #title by implementing it as a concrete method. We still see <h1>Dashboard</h1> when we visit /dashboard.

Exposures

There is another source for our context: exposures. They are a payload that comes from the action.

  1. # apps/web/controllers/dashboard/index.rb
  2. module Web
  3. module Controllers
  4. module Dashboard
  5. class Index
  6. include Web::Action
  7. expose :title
  8. def call(params)
  9. @title = 'Dashboard'
  10. end
  11. end
  12. end
  13. end
  14. end

We can remove #title from our view, to get the same output when accessing /dashboard.

  1. # apps/web/views/dashboard/index.rb
  2. module Web
  3. module Views
  4. module Dashboard
  5. class Index
  6. include Web::View
  7. end
  8. end
  9. end
  10. end

Rendering context for a template is made of view methods and exposures.

The objects exposed in the controller action are available in the corresponding view. So the values can also be modified, wrapped or reused in some other way. Assuming that the title is exposed in the action, it can be accessed as follows:

  1. # apps/web/views/dashboard/index.rb
  2. module Web
  3. module Views
  4. module Dashboard
  5. class Index
  6. include Web::View
  7. def full_title
  8. "The title: " + title
  9. end
  10. end
  11. end
  12. end
  13. end

Custom Rendering

Hanami performs rendering by calling #render on a view and it expects a string in return. The benefit of an object-oriented approach is the ability to easily diverge from default behavior.

We can override that method to define a custom rendering policy.

  1. # apps/web/views/dashboard/index.rb
  2. module Web
  3. module Views
  4. module Dashboard
  5. class Index
  6. include Web::View
  7. def render
  8. raw %(<h1>Dashboard</h1>)
  9. end
  10. end
  11. end
  12. end
  13. end

Once again our output is still the same, but the template isn’t used at all.

If a view overrides #render the output MUST be a string that will be the body of the response. The template isn’t used and it can be deleted.

Bypass Rendering

If an action assigns the body of the response with #body=, the rendering of the view is bypassed.