ActionView 中的 Yield 魔法是如何发挥作用的?

发布于 2024-08-28 08:05:52 字数 456 浏览 14 评论 0原文

我是查看 content_for 的工作原理并观察 capture_erb_with_buffer 中的 block.call方法。它显然神奇地写入了缓冲区变量,然后该变量被修剪。但是,我认为这已被弃用,您现在可以调用 <%=yield :tag%> 。这是如何运作的?如果我从 ERB 模板调用yield,那么yield会到哪里?

一个简单的代码示例来说明这一点将不胜感激。

I was looking at how content_for works and observed the block.call in the capture_erb_with_buffer method. It apparently magically writes to the buffer variable which is then pruned. However, this I believe is deprecated and you can just call <%=yield :tag%> now. How does this work? If I call yield from an ERB template where does that yield to?

A simple code sample to illustrate the point would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一人独醉 2024-09-04 08:05:52

我不确定 yield 在 ERB 级别上如何发挥作用,但我确实知道它在应用于布局时如何工作。

下面是一个示例布局.html.erb 文件:

<html>
  <head>
    <title> <%= @title || 'Plain Title' %> </title>
    <%= yield :head %>
  </head>
<body>
  <div id='menu'>
    <%= yield :menu %>
  </div>
  <div id='content'>
    <%= yield %>
  </div>
  <div id='footer'>
    <%= yield :footer %>
  </div>
</body>

我定义了 4 个产量(:head、:menu、:footer 和 default)和一个实例变量@title。

现在控制器操作可以渲染插入这些点的视图。请注意,视图在布局之前渲染,因此我可以在视图中定义像 @title 这样的变量,并在布局中定义它。

示例视图:
关于页面

<% @title = 'About' %>
<% content_for :menu do %>
  <%= link_to 'Back to Home', :action => :home %>
<% end %>

We rock!

<% content_for :footer do %>
  An Illinois based company.
<% end %>

编辑页面

<% @title = 'Edit' %>
<% content_for :head do %>
  <style type='text/css'> .edit_form div {display:inline-block;} </style>
<% end %>

<% form_for :thing, :html => {:class => 'edit_form'} do |f| %>
   ...
<% end %>

您可以混合和匹配要放入数据的产量,content_for :something 中发生的内容将插入到匹配的 yield :something 中> 在布局文件中。

它甚至适用于部分,部分可以插入自己的 content_for :something 块,该块将与任何其他 content_for 调用一起添加。

I'm not certain how yield functions on the ERB level, but I do know how it works when applied to layouts.

Heres a sample layout.html.erb file:

<html>
  <head>
    <title> <%= @title || 'Plain Title' %> </title>
    <%= yield :head %>
  </head>
<body>
  <div id='menu'>
    <%= yield :menu %>
  </div>
  <div id='content'>
    <%= yield %>
  </div>
  <div id='footer'>
    <%= yield :footer %>
  </div>
</body>

I have defined 4 yields(:head, :menu, :footer, and default) and an instance variable @title.

Now controller actions can render views that slot into these spots. Note that the view renders before the layout, so I can define a variable like @title in a view and have it defined in the layout.

Sample views:
An About page

<% @title = 'About' %>
<% content_for :menu do %>
  <%= link_to 'Back to Home', :action => :home %>
<% end %>

We rock!

<% content_for :footer do %>
  An Illinois based company.
<% end %>

An Edit page

<% @title = 'Edit' %>
<% content_for :head do %>
  <style type='text/css'> .edit_form div {display:inline-block;} </style>
<% end %>

<% form_for :thing, :html => {:class => 'edit_form'} do |f| %>
   ...
<% end %>

You can mix and match what yields you want to put data in, and what occurs in the content_for :something will be inserted in the matching yield :something in the layout file.

It even works for partials, a partial can insert its own content_for :something block which will get added with any other content_for calls.

弃爱 2024-09-04 08:05:52

ActionView::Base 中名为 execute 的小方法解释了这一切。
http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/base.rb&q=capture_helper.rb& d=5&l=337

  def execute(template)
    send(template.method, template.locals) do |*names|
      instance_variable_get "@content_for_#{names.first || 'layout'}"
    end
  end

do |*names|... end 块是接收 yield 的块。您会注意到 @content_for_#{names.first}content_for 流程中设置的变量相匹配。

它是从 #render 中的 AV::TemplateHandlers::Compilable 调用的,我也会假设其他地方。

  def render(template)
    @view.send :execute, template
  end

http://google.com/codesearch/p?hl= en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb&q=execute&exact_package=git://github.com/payalgupta/todo-list.git&sa=N&cd= 17&ct=rc&l=28

This little tiny method called execute in ActionView::Base explains it all.
http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/base.rb&q=capture_helper.rb&d=5&l=337

  def execute(template)
    send(template.method, template.locals) do |*names|
      instance_variable_get "@content_for_#{names.first || 'layout'}"
    end
  end

The do |*names|... end block is the one receiving the yield. You'll notice that the @content_for_#{names.first} matches up with the variable being set in the content_for process.

It's called from AV::TemplateHandlers::Compilable in #render, and I would assume other places as well.

  def render(template)
    @view.send :execute, template
  end

http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb&q=execute&exact_package=git://github.com/payalgupta/todo-list.git&sa=N&cd=17&ct=rc&l=28

心作怪 2024-09-04 08:05:52

简单地说:

在方法中调用yield会执行通过块传递给该方法的代码。

例如,

def my_method
  yield
end

my_method { puts "Hello" }
my_method { puts "World" }

这 5 行将在屏幕上生成以下输出,

Hello
World

请参阅以下页面,了解有关 Ruby 中的产量的精彩讨论: 红宝石产量

Simply:

calling yield in a method executes code that was passed to the method via a block.

For instance

def my_method
  yield
end

my_method { puts "Hello" }
my_method { puts "World" }

these 5 lines will produce the following output to the screen

Hello
World

See the following page for a nice discussion of yield in Ruby: Ruby Yield

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文