跳至内容 跳至搜索

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 调用本身将仅返回一个包含渲染结果的字符串。输出嵌入将其写入当前模板。

但是您不必局限于静态包含。模板可以通过使用常规嵌入标签定义的实例变量在它们之间共享变量。像这样

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

现在,页眉可以获取 @page_title 变量并将其用于输出 title 标签

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

将局部变量传递给子模板

您可以通过使用一个哈希,将变量名作为键,对象作为值,将局部变量传递给子模板

<%= 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 Overview 中阅读有关严格局部变量的更多信息。

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

Attributes

[R] lookup_context
[R] view_renderer

类公共方法

cache_template_loading()

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

cache_template_loading=(value)

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

inspect()

# File actionview/lib/action_view/base.rb, line 212
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 264
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
      public_send_line = __LINE__ - 2
      frame = argument_error.backtrace_locations[1]
      if frame.path == __FILE__ && frame.lineno == public_send_line
        raise StrictLocalsError.new(argument_error, @current_template)
      end
      raise
    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