Layouts are special views, that render the "fixed" part of the HTML markup. This is the part that doesn't change from page to page (perhaps navigation, sidebar, header, footer, etc.)
When we generate a new application, there is a default layout called
Web::Views::ApplicationLayout with a
It comes with a very basic HTML5 wireframe.
<!DOCTYPE HTML> <html> <head> <title>Web</title> </head> <body> <%= yield %> </body> </html>
The most interesting part is
<%= yield %>.
It's replaced at the runtime with the output of a view.
The order for rendering is first the view, and then the layout.
The context for a layout template is made of the layout and the current view. The latter has higher priority.
Imagine having the following line
<title><%= page_title %></title>.
If both the layout and the view implement
page_title, Hanami will use the one from the view.
The default layout is defined in an application's configuration.
# apps/web/application.rb module Web class Application < Hanami::Application configure do layout :application end end end
Hanami transforms the layout name in the application's configuration, by appending the
Layout suffix. For example,
layout :application corresponds to
If we want to disable a layout for a view, we can use a DSL for that:
# apps/web/views/dashboard/index.rb module Web::Views::Dashboard class Index include Web::View layout false end end
If we want to turn off this feature entirely, we can set
layout nil into the application's configuration.
Sometimes it's useful to have more than one layout.
For example, if the
application.html.erb template contains navigation elements, and we want an entirely different layout, without navigation elements, for a login page, we can create a
login.html.erb layout template.
Assuming we have a
Web::Actions::UserSessions::New action to log a user in, we can create a
login.html.erb template right next to the default
Then we need to create a new
Web::Views::LoginLayout class, which will use the new layout template. This file can be named
app/web/views/login_layout.rb(right next to the default
module Web module Views class LoginLayout include Web::Layout end end end
Now, in our
app/web/views/user_sessions/new.rb we can specify you'd like to use the login layout for this View:
module Web::Views::UserSessions class New include Web::View layout :login end end
And we can add
layout :login to any other View in this app that should use this same layout.
Given the following template for a layout:
With following views:
module Web::Views::Books class Index include Web::View end end
The first view doesn't respond to
Our second object (
Web::Views::Books::Show) responds to that method, so the result will be included in the final markup.