当只有导航依赖于控制器时可用的布局方法

Available approaches for layouts when only the navigation depends on the controller

给定一个带有依赖于当前控制器的导航栏的布局:

# layout.html.slim
doctype html
html
  body
    main
      = render partial: 'domain_nav'
      = yield

该应用有多个业务领域,比方说 "Clients"、"Tasks"、"Books",它们有自己独特的导航(clients_navtasks_navbooks_nav)。

每个部分都有多个控制器,视图会根据控制器业务域显示导航(例如Clients::CompaniesController会显示clients_nav)。

上面的 html 是简化的,但基本上,所有控制器共享相同的布局,除了 domain_nav 取决于域。

我看到了几种处理方法:


# 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

如果您不能按这样的名称空间对控制器进行分组,那么只有在您有管理面板的情况下,您仍然可以采用这种方法的不同变体。我们可以创建一个 table,将 controller_name 映射到 navigation_path。此 table 上的条目只能从管理面板填充。

我走了一条不同的路。由于控制器有责任决定布局,我认为 rails 让它也决定导航的方式。

就像有一个 "layout" 声明一样,我现在有一个 "navigation" 声明。控制器的外观如下:

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