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
现在,当处理索引操作的新请求时,布局将根据访问者是否登录而有所不同。
如果您想使用内联方法,例如 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 的所有操作(除 rss
操作外)分配“weblog_standard”作为布局,rss
操作将直接渲染,而不会在渲染的视图周围包装布局。
:only
和 :except
条件都可以接受任意数量的方法引用,因此 except: [ :rss, :text_only ]
是有效的,except: :rss
也是有效的。
在操作渲染调用中使用不同的布局
如果您的大部分操作使用相同的布局,则定义如上所述的控制器范围布局非常有意义。 有时您会遇到一些例外,其中一个操作希望使用与控制器其余部分不同的布局。 您可以通过将 :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