Action View 布局¶ ↑
Layouts 颠倒了在许多模板中包含共享头部和尾部的常见模式,以隔离重复设置中的更改。包含模式的页面如下所示:
<%= render "application/header" %> Hello World <%= render "application/footer" %>
这种方法是将公共结构与变化的内容隔离的好方法,但它很冗长,如果您想更改这两个包含的结构,您将不得不更改所有模板。
使用布局,您可以颠倒过来,让公共结构知道在哪里插入变化的内容。这意味着头部和尾部只在一个地方提到,如下所示:
// The header part of this layout <%= yield %> // The footer part of this layout
然后,您将拥有类似以下内容的内容页面:
hello world
在渲染时,内容页面将被计算出来,然后插入到布局中,如下所示:
// The header part of this layout hello world // The footer part of this layout
访问共享变量¶ ↑
Layouts 可以访问在内容页面中指定的变量,反之亦然。这允许您使用在渲染前不会实现的引用来创建布局。
<h1><%= @page_title %></h1> <%= yield %>
…以及在渲染时实现这些引用的内容页面。
<% @page_title = "Welcome" %> Off-world colonies offers you a chance to start a new life
渲染后的结果是:
<h1>Welcome</h1> Off-world colonies offers you a chance to start a new life
布局分配¶ ↑
您可以声明式地指定一个布局(使用 `layout` 类方法),或者给它一个与您的控制器同名的布局,并将其放在 `app/views/layouts` 目录下。如果子类没有指定布局,它将通过普通的 Ruby 继承来继承其布局。
例如,如果您有一个 `PostsController` 和一个名为 `app/views/layouts/posts.html.erb` 的模板,该模板将用于 `PostsController` 中的所有操作以及继承自 `PostsController` 的控制器。
如果您使用模块,例如 `Weblog::PostsController`,您将需要一个名为 `app/views/layouts/weblog/posts.html.erb` 的模板。
由于您所有的控制器都继承自 `ApplicationController`,如果未指定或提供其他布局,它们将使用 `app/views/layouts/application.html.erb`。
继承示例¶ ↑
class BankController < ActionController::Base # bank.html.erb exists class ExchangeController < BankController # exchange.html.erb exists class CurrencyController < BankController class InformationController < BankController layout "information" class TellerController < InformationController # teller.html.erb exists class EmployeeController < InformationController # employee.html.erb exists layout nil class VaultController < BankController layout :access_level_layout class TillController < BankController layout false
在这些示例中,我们有三种隐式查找场景:
-
BankController使用“bank”布局。 -
ExchangeController使用“exchange”布局。 -
CurrencyController从 `BankController` 继承布局。
然而,当显式设置布局时,显式设置的布局优先。
-
InformationController使用“information”布局,这是显式设置的。 -
TellerController也使用“information”布局,因为父级显式设置了它。 -
EmployeeController使用“employee”布局,因为它将布局设置为 `nil`,从而重置了父级配置。 -
VaultController通过调用 `access_level_layout` 方法动态选择布局。 -
TillController完全不使用布局。
布局类型¶ ↑
Layouts 本质上就是普通的模板,但是这个模板的名称不必是静态指定的。有时您想根据运行时信息(例如用户是否已登录)来交替使用布局。这可以通过将方法引用指定为符号或使用内联方法(作为 proc)来完成。
方法引用是变量布局的首选方法,用法如下:
class WeblogController < ActionController::Base layout :writers_and_readers def index # fetching posts end private def writers_and_readers logged_in? ? "writer_layout" : "reader_layout" end end
现在,当处理对 `index` 操作的新请求时,布局将根据访问者是否登录而变化。
如果您想使用内联方法,例如 proc,请执行以下操作:
class WeblogController < ActionController::Base layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } end
如果未给 proc 提供参数,它将在当前控制器的上下文中进行评估。
class WeblogController < ActionController::Base layout proc { logged_in? ? "writer_layout" : "reader_layout" } end
当然,指定布局最常见的方式仍然是作为纯模板名称:
class WeblogController < ActionController::Base layout "weblog_standard" end
模板将始终在 `app/views/layouts/` 文件夹中查找。但您也可以直接指向 `layouts` 文件夹。`layout "layouts/demo"` 等同于 `layout "demo"`。
将布局设置为 `nil` 会强制在文件系统中查找,如果不存在则回退到父行为。将布局设置为 `nil` 有助于重新启用模板查找,从而覆盖父级中先前设置的配置。
class ApplicationController < ActionController::Base layout "application" end class PostsController < ApplicationController # Will use "application" layout end class CommentsController < ApplicationController # Will search for "comments" layout and fall back to "application" layout layout nil end
条件布局¶ ↑
如果您有一个默认应用于控制器所有操作的布局,您仍然可以选择渲染给定操作或一组操作而不使用布局,或者将布局限制为单个操作或一组操作。`:only` 和 `:except` 选项可以传递给 `layout` 调用。例如:
class WeblogController < ActionController::Base layout "weblog_standard", except: :rss # ... end
这将为 `WeblogController` 分配“weblog_standard”作为布局,用于所有操作,除了 `rss` 操作,该操作将直接渲染,而不会包装布局。
`:only` 和 `:except` 条件都可以接受任意数量的方法引用,因此 `except: [ :rss, :text_only ]` 与 `except: :rss` 都是有效的。
在 action render 调用中使用不同的布局¶ ↑
如果您的绝大多数操作都使用相同的布局,那么定义一个控制器范围的布局是有意义的,如上所述。有时会有例外,一个操作想使用与控制器其余部分不同的布局。您可以通过将 `:layout` 选项传递给 `render` 调用来实现此目的。例如:
class WeblogController < ActionController::Base layout "weblog_standard" def help render action: "help", layout: "help" end end
这将覆盖控制器范围的“weblog_standard”布局,并将使用“help”布局渲染 `help` 操作,而不是。
实例公共方法
action_has_layout?() 链接
控制一个操作是否应该使用布局进行渲染。如果您想禁用当前操作的任何 `layout` 设置,以便它在没有布局的情况下进行渲染,那么要么在控制器中覆盖此方法以返回 `false`,要么在渲染之前将 `action_has_layout` 属性设置为 `false`。
来源: 显示 | 在 GitHub 上
# File actionview/lib/action_view/layouts.rb, line 372 def action_has_layout? @_action_has_layout end