v7.0.0
更多資訊請前往 rubyonrails.org: 更多在 Ruby on Rails

Action View 概述

閱讀本指南後,您將瞭解:

1 Action View 是什麼?

在 Rails 中,Web 請求由 Action Controller 和 Action View 處理。通常,Action Controller 涉及與資料庫通訊並在必要時執行 CRUD actions。 Action View 然後負責編譯回應。

Action View 模板是在與 HTML 混合的標籤中使用嵌入的 Ruby 編寫的。為了避免模板程式碼混亂,一些幫助類提供了表單、日期和字串的通用行為。隨著應用程式的發展,嚮應用程式新增新的 helpers 也很容易。

Action View 的某些特性與 Active Record 相關,但這並不意味著 Action View 依賴於 Active Record。 Action View 是一個獨立的包,可以與任何型別的 Ruby 庫一起使用。

2 在 Rails 中使用 Action View

對於每個 controller,在 app/views 目錄中有一個關聯的目錄,該目錄包含構成與該 controller 關聯的 views 的模板檔案。這些檔案用於顯示由每個 controller action 產生的檢視。

讓我們來看看 Rails 在使用 scaffold 生成器建立新資源時預設做了什麼:

$ bin/rails generate scaffold article
      [...]
      invoke  scaffold_controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      create      app/views/articles/index.html.erb
      create      app/views/articles/edit.html.erb
      create      app/views/articles/show.html.erb
      create      app/views/articles/new.html.erb
      create      app/views/articles/_form.html.erb
      [...]

There is a naming convention for views in Rails. Typically, the views share their name with the associated controller action, as you can see above. 例如,articles_controller.rb 的索引 controller action 將使用 app/views/articles 目錄中的 index.html.erb view 檔案。 返回給客戶端的完整 HTML 由此 ERB 檔案、包裝它的佈局模板以及 view 可能引用的所有部分的組合組成。在本指南中,您將找到關於這三個元件中的每一個的更詳細的文件。

3 模板、區域性和佈局

如前所述,最終的 HTML 輸出是三個 Rails 元素的組合:TemplatesPartialsLayouts。 下面是他們每個人的簡要介紹 view。

3.1 模板

Action View 模板可以用多種方式編寫。如果模板檔案具有 .erb 副檔名,則它使用 ERB(嵌入式 Ruby)和 HTML 的混合。如果模板檔案具有 .builder 副檔名,則使用 Builder::XmlMarkup 庫。

Rails 支援多種模板系統,並使用副檔名來區分它們。例如,使用 ERB 模板系統的 HTML 檔案將使用 .html.erb 作為副檔名。

3.1.1 ERB

在 ERB 模板中,可以使用 <% %><%= %> 標籤包含 Ruby 程式碼。 <% %> 標籤用於執行不返回任何內容(例如條件、迴圈或塊)的 Ruby 程式碼,而 <%= %> 標籤用於需要輸出時。

考慮以下名稱迴圈:

<h1>Names of all the people</h1>
<% @people.each do |person| %>
  Name: <%= person.name %><br>
<% end %>

使用正常嵌入標籤 (<% %>) 設定迴圈,並使用輸出嵌入標籤 (<%= %>) 插入名稱。請注意,這不僅僅是一個使用建議:正常輸出函式(例如 printputs 不會透過 ERB 模板渲染到 view。所以這是錯誤的:

<%# WRONG %>
Hi, Mr. <% puts "Frodo" %>

要抑制前導和尾隨空格,您可以將 <%- -%><%%> 互換使用。

3.1.2 生成器

Builder 模板是 ERB 的更具程式性的替代方案。它們對於生成 XML 內容特別有用。名為 xml 的 XmlMarkup 物件可自動用於副檔名為 .builder 的模板。

以下是一些基本示例:

xml.em("emphasized")
xml.em { xml.b("emph & bold") }
xml.a("A Link", "href" => "https://rubyonrails.org")
xml.target("name" => "compile", "option" => "fast")

這將產生:

<em>emphasized</em>
<em><b>emph &amp; bold</b></em>
<a href="https://rubyonrails.org">A link</a>
<target option="fast" name="compile" />

任何帶有塊的方法都將被視為在塊中帶有巢狀標記的 XML 標記標記。例如,以下內容:

xml.div {
  xml.h1(@person.name)
  xml.p(@person.bio)
}

會產生類似的東西:

<div>
  <h1>David Heinemeier Hansson</h1>
  <p>A product of Danish Design during the Winter of '79...</p>
</div>

以下是 Basecamp 上實際使用的完整 RSS 示例:

xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title(@feed_title)
    xml.link(@url)
    xml.description "Basecamp: Recent items"
    xml.language "en-us"
    xml.ttl "40"

    for item in @recent_items
      xml.item do
        xml.title(item_title(item))
        xml.description(item_description(item)) if item_description(item)
        xml.pubDate(item_pubDate(item))
        xml.guid(@person.firm.account.url + @recent_items.url(item))
        xml.link(@person.firm.account.url + @recent_items.url(item))
        xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
      end
    end
  end
end
3.1.3 Jbuilder

Jbuilder 是一個寶石 由 Rails 團隊維護幷包含在預設的 Rails Gemfile 中。 它類似於 Builder,但用於生成 JSON,而不是 XML。

如果沒有,可以將以下內容新增到 Gemfile

gem 'jbuilder'

一個名為 json 的 Jbuilder 物件會自動提供給模板使用 .jbuilder 擴充套件。

這是一個基本示例:

json.name("Alex")
json.email("alex@example.com")

會產生:

{
  "name": "Alex",
  "email": "alex@example.com"
}

請參閱 Jbuilder 文件 瞭解 更多示例和資訊。

3.1.4 模板快取

預設情況下,Rails 會將每個模板編譯為一個方法來呈現它。在開發環境中,當你修改一個模板時,Rails 會檢查檔案的修改時間並重新編譯它。

3.2 區域性

部分模板——通常簡稱為“部分”——是另一種將渲染過程分解為更易於管理的塊的工具。使用部分,您可以從模板中提取程式碼片段以分離檔案,並在整個模板中重複使用它們。

3.2.1 命名部分

要將部分渲染為 view 的一部分,請使用 view 中的 render 方法:

<%= render "menu" %>

這將在正在渲染的檢視中渲染一個名為 _menu.html.erb 的檔案。注意前導下劃線字元:partials 用前導下劃線命名,以差別於正常的 views,即使它們被引用時沒有下劃線。即使您從另一個資料夾中提取部分內容也是如此:

<%= render "shared/menu" %>

該程式碼將從 app/views/shared/_menu.html.erb 中提取部分內容。

3.2.2 使用 Partials 來簡化 Views

使用部分的一種方法是將它們視為子程式的等價物;一種將細節移出 view 的方法,以便您可以更輕鬆地掌握正在發生的事情。例如,您可能有一個如下所示的 view:

<%= render "shared/ad_banner" %>

<h1>Products</h1>

<p>Here are a few of our fine products:</p>
<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

<%= render "shared/footer" %>

在這裡,_ad_banner.html.erb_footer.html.erb 部分可以包含在應用程式中的許多頁面之間共享的內容。當您專注於特定頁面時,您無需檢視這些部分的詳細資訊。

3.2.3 render 沒有 partiallocals 選項

在上面的例子中,render 有 2 個選項:partiallocals。但是如果 這些是您要傳遞的唯一選項,您可以跳過使用這些選項。 例如,而不是:

<%= render partial: "product", locals: { product: @product } %>

你也可以這樣做:

<%= render "product", product: @product %>
3.2.4 asobject 選項

預設情況下,ActionView::Partials::PartialRenderer 的物件位於與模板同名的區域性變數中。所以,給定:

<%= render partial: "product" %>

_product 部分中,我們將在區域性變數 product 中得到 @product, 好像我們寫過:

<%= render partial: "product", locals: { product: @product } %>

object選項可以直接指定哪個物件渲染到partial中;當模板的物件在別處(例如在不同的實例變數或區域性變數中)時很有用。

例如,而不是:

<%= render partial: "product", locals: { product: @item } %>

我們會這樣做:

<%= render partial: "product", object: @item %>

使用 as 選項,我們可以為所述區域性變數指定不同的名稱。例如,如果我們希望它是 item 而不是 product 我們會這樣做:

<%= render partial: "product", object: @item, as: "item" %>

這相當於

<%= render partial: "product", locals: { item: @item } %>
3.2.5 渲染集合

通常,模板需要遍歷集合併為每個元素呈現子模板。此模式已作為單一方法實現,該方法接受陣列併為陣列中的每個元素呈現部分。

所以這個渲染所有產品的例子:

<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

可以改寫成一行:

<%= render partial: "product", collection: @products %>

當使用集合呼叫區域性時,區域性的各個實例可以透過以區域性命名的變數訪問正在呈現的集合成員。本例中partial為_product,在其中可以參考product獲取正在渲染的集合成員。

您可以使用速記語法來呈現集合。假設 @productsProduct 實例的集合,您可以簡單地編寫以下內容來產生相同的結果:

<%= render @products %>

Rails 透過檢視集合中的模型名稱來確定要使用的部分名稱,在本例中為 Product。事實上,你甚至可以使用這個速記來渲染由不同 models 的實例組成的集合,Rails 會為集合的每個成員選擇合適的部分。

3.2.6 墊片模板

您還可以使用 :spacer_template 選項指定要在主要部分的實例之間呈現的第二部分:

<%= render partial: @products, spacer_template: "product_ruler" %>

Rails 將在每對 _product 部分之間渲染 _product_ruler 部分(沒有傳遞給它的資料)。

3.3 佈局

佈局可用於圍繞 Rails controller actions 的結果渲染一個通用的 view 模板。通常,Rails 應用程式將有幾個頁面將在其中呈現的佈局。例如,一個站點可能有一個用於登入使用者的佈局,另一個用於站點的營銷或銷售端。登入的使用者佈局可能包括頂級導航,它應該存在於許多 controller actions 中。 SaaS 應用程式的銷售佈局可能包括“定價”和“聯絡我們”頁面等內容的頂級導航。您希望每個佈局都有不同的外觀和感覺。您可以在 Rails 中的佈局和渲染 指南中詳細瞭解佈局。

4 部分佈局

Partials 可以應用自己的佈局。這些佈局與應用於 controller action 的佈局不同,但它們的工作方式相似。

假設我們要在頁面上顯示一篇文章,為了顯示目的,該文章應該包含在 div 中。首先,我們將建立一個新的 Article

Article.create(body: 'Partial Layouts are cool!')

show 模板中,我們將渲染包裹在 box 佈局中的 _article 部分:

文章/show.html.erb

<%= render partial: 'article', layout: 'box', locals: { article: @article } %>

box 佈局簡單地將 _article 部分包裝在 div 中:

文章/_box.html.erb

<div class='box'>
  <%= yield %>
</div>

請注意,部分佈局可以訪問傳遞到 render 呼叫中的本地 article 變數。但是,與應用程式範圍的佈局不同,部分佈局仍然具有下劃線字首。

您還可以在部分佈局中呈現程式碼塊,而不是呼叫 yield。例如,如果我們沒有 _article 部分,我們可以這樣做:

文章/show.html.erb

<% render(layout: 'box', locals: { article: @article }) do %>
  <div>
    <p><%= article.body %></p>
  </div>
<% end %>

假設我們使用上面相同的 _box 部分,這將產生與前一個示例相同的輸出。

5 View 路徑

渲染回應時,controller 需要解析不同的位置 views 位於。預設情況下,它只在 app/views 目錄中查詢。

我們可以新增其他位置並在解決時給它們一定的優先順序 使用 prepend_view_pathappend_view_path 方法的路徑。

5.1 前置 view 路徑

例如,當我們想將 views 放在不同的 子域的目錄。

我們可以使用以下方法來做到這一點:

prepend_view_path "app/views/#{request.subdomain}"

那麼在解析views的時候,Action View會先在這個目錄中查詢。

5.2 追加 view 路徑

同樣,我們可以附加路徑:

append_view_path "app/views/direct"

這會將 app/views/direct 新增到查詢路徑的末尾。

6 Helpers

Rails 提供了許多 helper 方法與 Action View 一起使用。其中包括以下方法:

  • 格式化日期、字串和數字
  • 建立指向影象、影片、樣式表等的 HTML 連結...
  • 消毒內容
  • 建立表單
  • 本地化內容

您可以在 Action View Helpers 指南Action View 表格 Helpers 指南

7 本地化的 Views

Action View 能夠根據當前語言環境呈現不同的模板。

例如,假設您有一個 ArticlesController 和一個節目 action。預設情況下,呼叫此 action 將呈現 app/views/articles/show.html.erb。但是如果你設定了 I18n.locale = :de,那麼 app/views/articles/show.de.html.erb 將被渲染。如果本地化模板不存在,則將使用未修飾的版本。這意味著您不需要為所有情況提供本地化的 views,但如果可用,它們將是首選和使用的。

您可以使用相同的技術來本地化公共目錄中的救援檔案。例如,設定 I18n.locale = :de 並建立 public/500.de.htmlpublic/404.de.html 將允許您擁有本地化的救援頁面。

由於 Rails 不限制用於設定 I18n.locale 的 symbols,因此您可以利用此係統根據您喜歡的任何內容顯示不同的內容。例如,假設您有一些“專家”使用者應該看到與“普通”使用者不同的頁面。您可以將以下內容新增到 app/controllers/application.rb

before_action :set_expert_locale

def set_expert_locale
  I18n.locale = :expert if current_user.expert?
end

然後你可以建立像 app/views/articles/show.expert.html.erb 這樣的特殊 views 只顯示給專家使用者。

您可以閱讀有關 Rails 國際化 (I18n) API 此處 的更多資訊。

回饋

我們鼓勵您幫助提高本指南的品質。

如果您發現任何拼寫錯誤或資訊錯誤,請提供回饋。 要開始回饋,您可以閱讀我們的 回饋 部分。

您還可能會發現不完整的內容或不是最新的內容。 請務必為 main 新增任何遺漏的文件。假設是 非穩定版指南(edge guides) 請先驗證問題是否已經在主分支上解決。 請前往 Ruby on Rails 指南寫作準則 查看寫作風格和慣例。

如果由於某種原因您發現要修復的內容但無法自行修補,請您 提出 issue

關於 Ruby on Rails 的任何類型的討論歡迎提供任何文件至 rubyonrails-docs 討論區