2012-01-24 69 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'。萬分感謝! –