2012-01-24 33 views
1

我有一对Rails助手,其中一个是为了接受一个块,另一个只是呈现一个按钮。下面是简化版本的助手定义:如何从Ruby块中的多个语句生成结果?

def nav_wrapper(nav_at, id, css_class, &block) 
    "<ul class="complicated">\n #{yield} \n</ul>".html_safe 
end 

def nav_btn(nav_at, caption, id = caption.downcase.dasherize) 
    "Nav button codes goes here".html_safe 
end 

我试图做一些事情,这样我可以做这样的事情:

<%= nav_wrapper(@nav_at, "Top Nav", "class") do %> 
    <%= nav_btn(@nav_at, "Foo", "id") %> 
    <%= nav_btn(@nav_at, "Bar", "id") %> 
    <%= nav_wrapper(@nav_at, "Sub Nav", "class") do %> 
    <%= nav_btn(@nav_at, "SubFoo", "id") %> 
    <%= nav_btn(@nav_at, "SubBar", "id") %> 
    <% end %> 
<% end %> 

但是,在nav_wrapper方法yield只挑选了每个块的最后一个语句。所以在这个例子中,我得到了Top Nav包装,Foo和Bar都被跳过了,我得到了Sub Nav包装(是nav_wrapper块的最后一个语句),SubFoo被跳过了,我得到了SubBar(作为最后一个语句)内部nav_wrapper块)。

我知道这种行为的原因是代码块隐式返回最后一次评估值,但我知道有大量模板助手呈现所有插页式行(例如,form_for)。有人能帮我弄清楚这里的魔术是什么吗?

回答

3

编译ERB模板时,它将转换为将字符串添加到缓冲区的代码。 (查看ERB的源代码以查看我的意思。)来自Action View的方法如form_for执行该块,然后检索ERB缓冲区中的文本。

打开lib/ruby/1.9.1/gems/1.9.1文件夹,然后查找actionpack。打开任何版本的Action Pack,然后转到​​。在那里有一个名为capture的方法,form_for使用该方法来执行块并检索由ERB生成的文本。

如果你正在编写一个Rails助手,那么大概capture将可用于你的代码。如果没有,请尝试include ActionView::Helpers::CaptureHelper

+2

我测试过了!恢复@Alex所说的你应该用'capture(&block)'来代替'yield'。 – fguillen

+1

这个技巧。我在''nav_wrapper'方法的顶部添加了一行'body = capture(&block)',并用'body'代替'yield'。万分感谢! –