给定一个带有导航栏的布局,该导航栏取决于当前的控制器:
# layout.html.slim
doctype html
html
body
main
= render partial: 'domain_nav'
= yield
该应用程序有几个业务领域,让我们说“客户端”,“任务”,“书籍”,具有自己独特的导航(clients_nav
,tasks_nav
,books_nav
)。
每个部分都有几个控制器,视图将显示基于控制器业务域的导航(例如,Clients :: CompaniesController将显示clients_nav
)。
上面的html是简化的,但基本上,所有控制器共享相同的布局,除了依赖于域的domain_nav
。
我看到几种方法来处理:
content_for :navigation
中使用yield :navigation
:因为我们确定每个视图都显示导航,所以感觉不对render layout: 'clients/layout' do
:它可以工作但是然后i18n变得一团糟# 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' }
还有其他方法可以解决这个问题吗?你会挑选哪一个?为什么?
如果控制器可以按其命名空间分组,就像它们的导航名称一样,我将使用"use a helper and determine which nav to use based on the controller name"
方法。就像控制器名称以Clients
开头一样(例如,Clients::CompaniesController
),我们可以很容易地将它映射到clients_nav
。
def nav_path
if params[:controller].starts_with? "Client"
'clients/nav'
elsif params[:controller].starts_with? "Task"
'tasks/nav'
else
'books/nav'
end
end
如果您无法通过此类命名空间对控制器进行分组,则只有拥有管理面板时,您仍然可以使用此方法的不同变体。我们可以创建一个表格,将controller_name
映射到navigation_path
。此表上的条目只能从管理面板填充。
我采取了不同的方式。由于控制器负责决定布局,我认为这也是让它决定导航的轨道方式。
就像有一个“布局”声明,我现在有一个“导航”声明。这是控制器的样子:
class ClientsController < ApplicationController
navigation 'clients/nav'
…
end
class BooksController < ApplicationController
navigation 'books/nav'
…
end
而我只有一个布局:
doctype html
html
body
main
= render partial: navigation
= yield
导航方法在ApplicationController中声明:
class ApplicationController < ActionController::Base
helper_method :navigation
def self.navigation(path)
define_method :navigation do
path
end
end
end