跳至內容 跳至搜尋

Action View Base

Action View 範本可以用下列幾種方式撰寫。如果範本檔的副檔名是 .erb,那就表示它使用 erubi 範本系統,它可以將 Ruby 嵌入至 HTML 文件中。如果範本檔的副檔名是 .builder,那就表示使用 Jim Weirich 的 Builder::XmlMarkup 程式庫。

ERB

你可以使用 <% %><% -%><%= %> 等內嵌元素來觸發 ERB。當你需要輸出時,就可以使用 <%= %> 標籤組。針對名稱採用下方的迴圈:

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

這個迴圈是在正規的內嵌標籤 <% %> 中建立,並且使用輸出的內嵌標籤 <%= %> 來撰寫名稱。請注意,這不只是一個使用建議而已。一般的輸出函式,例如 print 或 puts,不適用於 ERB 範本。因此,以下寫法是錯誤的

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

如果您真的必須從函式內部撰寫,請使用 concat

當在除了標籤以外只包含空白的一行時,<% %> 會抑制前導空白和結尾空白(包括結尾的新行)。<% %><%- -%> 是相同的。但是,請注意 <%= %><%= -%> 不同:只有後者會移除結尾空白。

使用次範本

使用次範本可以避開冗長的重複,並在共用範本中萃取常見的顯示結構。典型的範例是使用標頭和頁尾(儘管 Action Pack 的方式會使用 Layouts

<%= render "application/header" %>
Something really specific and terrific
<%= render "application/footer" %>

正如您所見,我們對 render 方法使用輸出的內嵌。render 呼叫本身只會傳回一個存放著 render 結果的字串。輸出內嵌將結果寫入目前範本。

但是,您不需要限制自己在靜態包含中。範本可以使用透過正規的內嵌標籤定義的執行個體變數,在它們之間共用變數。像這樣

<% @page_title = "A Wonderful Hello" %>
<%= render "application/header" %>

現在,標頭可以拾取 @page_title 變數,並使用它來輸出一組標題標籤

<title><%= @page_title %></title>

傳遞區域變數至次範本

您可以使用一個將變數名稱當成 key、將物件當成值散列,來傳遞區域變數至次範本

<%= render "application/header", { headline: "Welcome", person: person } %>

現在可以在 application/header 中使用這個方法來存取:

Headline: <%= headline %>
First name: <%= person.first_name %>

可以將傳遞至次範本的區域變數當成一個散列,使用 local_assigns 散列來存取。這將讓您能夠以這種方式存取變數:

Headline: <%= local_assigns[:headline] %>

這可應用在您不確定是否已指派區域變數的情況中。或者,您也可以先使用 defined? headline 來檢查是否已指派變數,再開啟使用。

預設上,範本會將任何 locals 視為關鍵字參數來接受。如需限制範本接受的 locals,請加入 locals: 幻影註解

<%# locals: (headline:) %>

Headline: <%= headline %>

在區域變數為可選時,宣告一個具有預設值的關鍵字參數

<%# locals: (headline: nil) %>

<% unless headline.nil? %>
Headline: <%= headline %>
<% end %>

深入了解嚴謹區域變數,請參閱指南中的Action View 總覽

Template 快取

預設下,Rails 會將每個範本編譯成一個方法,以便呈現。當你變更一個範本時,Rails 會檢查檔案的修改時間,並在開發模式中重新編譯它。

Builder

Builder 範本是ERB一種更具程式化的替代方案。它們對於產生 XML 內容特別有用。一個 名為 xml 的 XmlMarkup 物件會自動提供給具有 .builder 擴充功能的範本。

以下是幾個基本範例

xml.em("emphasized")                                 # => <em>emphasized</em>
xml.em { xml.b("emph & bold") }                      # => <em><b>emph &amp; bold</b></em>
xml.a("A Link", "href" => "http://onestepback.org")  # => <a href="http://onestepback.org">A Link</a>
xml.target("name" => "compile", "option" => "fast")  # => <target option="fast" name="compile"\>
                                                     # NOTE: order of attributes is not specified.

具有區段的任何方法都會被視為一個 XML 標記標籤,在區段中會有巢狀標記。例如,下列範例會

xml.div do
  xml.h1(@person.name)
  xml.p(@person.bio)
end

產生類似於下列內容

<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"

    @recent_items.each do |item|
      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

有關 Builder 的更多資訊,請參閱原始碼

方法
#
C
I

屬性

[R] lookup_context
[R] view_renderer

類別公開的方法

cache_template_loading()

# File actionview/lib/action_view/base.rb, line 187
def cache_template_loading
  ActionView::Resolver.caching?
end

cache_template_loading=(value)

# File actionview/lib/action_view/base.rb, line 191
def cache_template_loading=(value)
  ActionView::Resolver.caching = value
end

inspect()

# File actionview/lib/action_view/base.rb, line 207
def inspect
  "#<ActionView::Base:#{'%#016x' % (object_id << 1)}>"
end

實例公開的方法

_run(method, template, locals, buffer, add_to_stack: true, has_strict_locals: false, &block)

# File actionview/lib/action_view/base.rb, line 261
def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals: false, &block)
  _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
  @current_template = template if add_to_stack
  @output_buffer = buffer

  if has_strict_locals
    begin
      public_send(method, locals, buffer, **locals, &block)
    rescue ArgumentError => argument_error
      raise(
        ArgumentError,
        argument_error.
          message.
            gsub("unknown keyword:", "unknown local:").
            gsub("missing keyword:", "missing local:").
            gsub("no keywords accepted", "no locals accepted").
            concat(" for #{@current_template.short_identifier}")
      )
    end
  else
    public_send(method, locals, buffer, &block)
  end
ensure
  @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
end

compiled_method_container()

# File actionview/lib/action_view/base.rb, line 287
    def compiled_method_container
      raise NotImplementedError, <<~msg.squish
        Subclasses of ActionView::Base must implement `compiled_method_container`
        or use the class method `with_empty_template_cache` for constructing
        an ActionView::Base subclass that has an empty cache.
      msg
    end

in_rendering_context(options)

# File actionview/lib/action_view/base.rb, line 295
def in_rendering_context(options)
  old_view_renderer  = @view_renderer
  old_lookup_context = @lookup_context

  if !lookup_context.html_fallback_for_js && options[:formats]
    formats = Array(options[:formats])
    if formats == [:js]
      formats << :html
    end
    @lookup_context = lookup_context.with_prepended_formats(formats)
    @view_renderer = ActionView::Renderer.new @lookup_context
  end

  yield @view_renderer
ensure
  @view_renderer = old_view_renderer
  @lookup_context = old_lookup_context
end