Given a layout with a navigation bar which depends on the current controller :
# layout.html.slim
doctype html
html
body
main
= render partial: 'domain_nav'
= yield
The app has several business domains, let's say "Clients", "Tasks", "Books", with their own distinct navigations (clients_nav
, tasks_nav
, books_nav
).
Each part has several controllers, and the view will display the navigation based on the controller business domain (e.g. the Clients::CompaniesController will display the clients_nav
).
The html above is simplified but basically, all controllers share the same layout except for the domain_nav
which depends on the domain.
I see several ways to handle that :
content_for :navigation
in each view and yield :navigation
: since we're sure that the navigation is displayed for each view,
this doesn't feel right eitherrender layout: 'clients/layout' do
: it works but then i18n becomes a mess# layouts/_shared.html.slim
doctype html
html
body
main
= render partial: nav_path
= yield
# layouts/clients.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'clients/nav' }
# layouts/tasks.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'tasks/nav' }
# layouts/books.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'books/nav' }
Are there other approaches to this problem ? Which one would you pick and why ?
I went a different way. Since it's the responsibility of the controller to decide of the layout, I thought it would be the rails way to let it also decide of the navigation.
So just like there is a "layout" declaration, I now have a "navigation" declaration. Here's what the controllers look like:
class ClientsController < ApplicationController
navigation 'clients/nav'
…
end
class BooksController < ApplicationController
navigation 'books/nav'
…
end
and I have just one layout:
doctype html
html
body
main
= render partial: navigation
= yield
The navigation method is declared in ApplicationController:
class ApplicationController < ActionController::Base
helper_method :navigation
def self.navigation(path)
define_method :navigation do
path
end
end
end