跳至內容 跳至搜尋

Action View 擷取幫手

CaptureHelper 公開方法,讓您擷取產生的標記,可在範本或版面配置檔檔案的其他部分使用。

它提供一種方法來透過 capture 將區塊擷取到變數中,以及一種方法來透過 content_for 擷取標記區塊以用於版面配置檔。

也會在使用串流回應時透過 provide 提供一種方法。請參閱 ActionController::Streaming 以取得更多資訊。

方法
C
P

個體公開方法

capture(*args, &block)

「capture」方法會將範本的部分內容擷取為字串物件。您接下來可以在範本、版面配置檔或幫手中任何位置使用這個物件。

「capture」方法可在 ERB 範本中使用…

<% @greeting = capture do %>
  Welcome to my shiny new web page!  The date and time is
  <%= Time.now %>
<% end %>

…以及 Builder (RXML) 範本。

@timestamp = capture do
  "The current timestamp is #{Time.now}."
end

然後,您可以在任何其他地方使用該變數。例如

<html>
<head><title><%= @greeting %></title></head>
<body>
<b><%= @greeting %></b>
</body>
</html>

「capture」回傳的是區塊產生的字串。例如

@greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
# File actionview/lib/action_view/helpers/capture_helper.rb, line 47
def capture(*args, &block)
  value = nil
  @output_buffer ||= ActionView::OutputBuffer.new
  buffer = @output_buffer.capture { value = yield(*args) }

  string = if @output_buffer.equal?(value)
    buffer
  else
    buffer.presence || value
  end

  case string
  when OutputBuffer
    string.to_s
  when ActiveSupport::SafeBuffer
    string
  when String
    ERB::Util.html_escape(string)
  end
end

content_for(name, content = nil, options = {}, &block)

呼叫 content_for 會將標記區塊儲存在識別碼中以供稍後使用。如要存取儲存的內容,您會將識別碼傳遞為參數至 content_for

注意:yield 仍可拿來擷取儲存的內容,但幫手中無法呼叫 yield,而 content_for 可以。

<% content_for :not_authorized do %>
  alert('You are not authorized to do that!')
<% end %>

然後,您可以在任何範本中使用 content_for :not_authorized

<%= content_for :not_authorized if current_user.nil? %>

這個用法等同於

<%= yield :not_authorized if current_user.nil? %>

不過,content_for 也可以在幫手中使用。

module StorageHelper
  def stored_content
    content_for(:storage) || "Your storage is empty"
  end
end

此幫手的工作方式就像一般幫手。

<%= stored_content %>

您也可以將 yield 語法和 yield 的現有呼叫同時用在版面配置檔中。例如

<%# This is the layout %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>My Website</title>
  <%= yield :script %>
</head>
<body>
  <%= yield %>
</body>
</html>

現在,我們來建立一個檢視,該檢視有 content_for 呼叫,會建立 script 識別碼。

<%# This is our view %>
Please login!

<% content_for :script do %>
  <script>alert('You are not authorized to view this page!')</script>
<% end %>

接著,您可以在另一個檢視中執行類似以下的動作

<%= link_to 'Logout', action: 'logout', remote: true %>

<% content_for :script do %>
  <%= javascript_include_tag :defaults %>
<% end %>

這樣做會在頁面上放置唯讀 JavaScript 檔案的 script 標籤;這個技巧在您只會在幾個檢視中使用這些腳本時很有用。

請注意, content_for 會針對特定識別碼合併 (預設) 給定的區塊順序。例如

<% content_for :navigation do %>
  <li><%= link_to 'Home', action: 'index' %></li>
<% end %>

在另一個地方

<% content_for :navigation do %>
  <li><%= link_to 'Login', action: 'login' %></li>
<% end %>

然後,在另一個範本或版面配置檔中,這種程式碼會按順序呈現兩個連結

<ul><%= content_for :navigation %></ul>

如果「flush」參數是 truecontent_for 會取代給定的區塊。例如

<% content_for :navigation do %>
  <li><%= link_to 'Home', action: 'index' %></li>
<% end %>

<%# Add some other content, or use a different template: %>

<% content_for :navigation, flush: true do %>
  <li><%= link_to 'Login', action: 'login' %></li>
<% end %>

然後,在另一個範本或版面配置檔中,這種程式碼只會呈現最後一個連結

<ul><%= content_for :navigation %></ul>

最後,可以透過參數傳遞簡單的內容

<% content_for :script, javascript_include_tag(:defaults) %>

警告:會忽略快取中的 content_for。因此,您不應將其用於會進行片斷快取的元素。

# File actionview/lib/action_view/helpers/capture_helper.rb, line 172
def content_for(name, content = nil, options = {}, &block)
  if content || block_given?
    if block_given?
      options = content if content
      content = capture(&block)
    end
    if content
      options[:flush] ? @view_flow.set(name, content) : @view_flow.append(name, content)
    end
    nil
  else
    @view_flow.get(name).presence
  end
end

content_for?(name)

content_for? 會檢查是否已使用 content_for 擷取任何內容。

有助於根據檢視中的內容,為版面的部分呈現不同樣貌。

<%# This is the layout %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>My Website</title>
  <%= yield :script %>
</head>
<body class="<%= content_for?(:right_col) ? 'two-column' : 'one-column' %>">
  <%= yield %>
  <%= yield :right_col %>
</body>
</html>
# File actionview/lib/action_view/helpers/capture_helper.rb, line 215
def content_for?(name)
  @view_flow.get(name).present?
end

provide(name, content = nil, &block)

content_for 相同,但使用串流時,會直接清空到版面中。換句話說,如果你要在呈現特定範本時,對相同的緩衝區串接多次,應使用 content_for,否則可以使用 provide 告訴版面停止尋找更多內容。

有關更多資訊,請參閱 ActionController::Streaming

# File actionview/lib/action_view/helpers/capture_helper.rb, line 194
def provide(name, content = nil, &block)
  content = capture(&block) if block_given?
  result = @view_flow.append!(name, content) if content
  result unless content
end