跳至內容 跳至搜尋

Action View Layouts

Layouts 反轉常見的模式,將共用標題和頁尾包含在許多範本中,以隔離重複設定中的變更。包含模式的頁面看起來像這樣

<%= render "application/header" %>
Hello World
<%= render "application/footer" %>

這種方法是讓共用結構與變更內容隔離的不錯方式,但它很冗長,如果您想變更這兩個包含的結構,您必須變更所有範本。

使用 Layouts,您可以反轉它,讓共用結構知道在何處插入變更內容。這表示僅在一個地方提及標題和頁尾,如下所示

// The header part of this layout
<%= yield %>
// The footer part of this layout

然後,您有看起來像這樣的內容頁面

hello world

在呈現時間,內容頁面會被計算,然後插入在 Layout 中,如下所示

// The header part of this layout
hello world
// The footer part of this layout

存取共用變數

Layouts 可以存取在內容頁面中指定的變數,反之亦然。這允許您使用在呈現時間之前不會具體化的參照建立 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 指派

您可以宣告指定 Layout (使用 layout 類別方法),或為其指定與您的控制器相同的名稱,並將其置於 app/views/layouts 中。如果子類別沒有指定 Layout,它會使用常規 Ruby 繼承繼承其 Layout。

例如,如果您有 PostsController 和一個名為 app/views/layouts/posts.html.erb 的範本,該範本會用在 PostsController 和繼承自 PostsController 的控制器中的所有動作。

如果您使用模組 (例如 Weblog::PostsController),您會需要一個名為 app/views/layouts/weblog/posts.html.erb 的範本。

由於您的所有控制器都繼承自 ApplicationController,如果未指定或提供其他 Layout,它們會使用 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」Layout。

  • ExchangeController 使用「exchange」Layout。

  • CurrencyController 從 BankController 繼承 Layout。

但是,當 Layout 被明確設定時,明確設定的 Layout 會勝出

  • InformationController 使用明確設定的「information」Layout。

  • TellerController 也使用「information」Layout,因為父項明確設定了它。

  • EmployeeController 使用「employee」Layout,因為它將 Layout 設定為 nil,重新設定父項組態。

  • VaultController 透過呼叫 access_level_layout 方法動態選擇 Layout。

  • TillController 完全不使用 Layout。

Layout 類型

Layouts 基本上就只是常規範本,但此範本的名稱不需要靜態指定。有時,您想根據執行時間資訊來交替 Layout,例如某人是否已登入。這可以透過將方法參照指定為符號,或使用內嵌方法 (以 proc 的形式) 來執行。

方法參照是可變 Layout 的首選方法,並且這樣使用

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 選項可以傳遞給佈局呼叫。例如

class WeblogController < ActionController::Base
  layout "weblog_standard", except: :rss

  # ...

end

這將指定「weblog_standard」為 WeblogController 的佈局,用於除 rss 動作以外的所有動作,並將直接呈現 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」動作。

命名空間
方法
A
包含模組

實例公開方法

action_has_layout?()

控制是否應使用佈局呈現動作。若要停用目前動作的任何 layout 設定,使其可在沒有佈局的情況下呈現,則請在控制器中覆寫此方法,使其傳回 false,或在呈現前將 action_has_layout 屬性設定為 false。

# File actionview/lib/action_view/layouts.rb, line 372
def action_has_layout?
  @_action_has_layout
end