#40
Jun 04, 2007

Blocks in View

If you try to create a helper method which accepts a block, you will run into a few gotchas. Learn the secrets of blocks in views in this episode.
Tags: views
Download (20.1 MB, 9:06)
alternative download for iPod & Apple TV (11.8 MB, 9:06)
<% side_section do %>
  This is on the side bar.
<% end %>

<% admin_area do %>
  <%= link_to "Edit Task", edit_task_path(@task) %>
<% end %>
# application_helper
def side_section(&block)
  @side_sections ||= []
  @side_sections << capture(&block)
end

def admin_area(&block)
  concat('<div class="admin">', block.binding)
  block.call
  concat("</div>", block.binding)
end

# or...
def admin_area(&block)
  if admin?
    concat content_tag(:div, capture(&block), :class => 'admin'), block.binding
  end
end

RSS Feed for Episode Comments 19 comments

1. chineseGuy Jun 04, 2007 at 01:11

Good example!
I google about "Variable Bindings in Ruby"
http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc
and,with your example,I understand it
tks!


2. weskycn Jun 04, 2007 at 02:01

thank you !
这个可是我的最爱噢,
找他找了很久了。。
in my blog ,i try to add siderbar ,
i think i can use this episode!!!!!!^_^


3. Rebort Jun 04, 2007 at 06:10

Wildly useful and solves a small problem I had with my views. Thanks, Ryan!


4. JEG2 Jun 04, 2007 at 06:25

I have just one small suggestion.

When you have Ruby wrap the block into an object for you (by adding a &block parameter), I think it's more consistent to use block.call over yield. Generally I thin you either want to go with a yield/block_given? strategy or a &block/block.call/block.nil? strategy, depending on the method you are writing. But it's probably best not to mix and match. In your examples, we need the block object to get the binding, so the latter is better.


5. Emil Jun 04, 2007 at 08:05

GOOD!!!!!


6. Ryan Bates Jun 04, 2007 at 08:10

@JEG2, thanks for the suggestion. I've seen the mix of yield and &block in other places as well (such as the source of fields_for) which is one reason I didn't think it mattered. But you know Ruby probably better than any of us here, so I'll try to stick with your suggestion. Thanks! :)


7. Jon Buda Jun 04, 2007 at 10:30

Excellent tips, I'll have to implement this soon. One question though...how does the use of blocks in the views work with caching? Does it at all or are there some limitations? Thanks, great screencasts. I look forward to the new ones all the time.


8. Ryan Bates Jun 04, 2007 at 13:47

I don't think there's any issues with caching. You just have to watch out for setting instance variables (like the side sections example). If you cache outside the block, the helper method won't be called every time and the instance variable won't be set.


9. weskycn Jun 04, 2007 at 23:58

哈哈,这里有这么多的中国同胞阿
1ster、 chineseGuy
你们都好么?


10. Brian Jul 31, 2007 at 21:43

How do you do something like yield(msg) in actionview?


11. Ryan Bates Jul 31, 2007 at 21:58

@Brian, you should be able to do that without any issues (just like any normal yield call). Is it not working?


12. Brian Jul 31, 2007 at 22:12

Well I mean it does but I want to surround it with tags. ie create div or a ul and then insert the yield(msg) result in it. No point in creating the ul or div if there's nothing to go in it. Do you have the site notify you when comments are posted cause that was ridiculously fast.


13. Ryan Bates Aug 01, 2007 at 07:33

Hmm, not entirely sure what you're asking, but eithe way it should work without any changes. See this pastie code for an example of passing a string to the block.

http://pastie.caboo.se/84044


14. Brian Aug 01, 2007 at 23:08

Sweet. That's exactly what I needed I didn't know you could pass an argument to capture


15. liusong1111 Aug 22, 2007 at 08:21

to weskycn:
Don't say anything not related to the topic. obeying the rule is the most polite than words,okey?
actually,I am a chinese too.
-------
blocks in view is powerful,especially with "capture"'s help.
I finished a "table_for" helper with the mechinism,the usage like this:
<% table_for :users do |t|
     t.column :full_name {|user| h user.first_name + " " + user.last_name}
     t.columns :age,:birthday
     t.columns :$edit,:$show
%>

<% t.erb_column('Destroy') do |user| %>
<% if user.name != 'xxx' %>
  <%= link_to 'Destroy',user_path(user),:method=>:delete %>
<% end %>
<% end
     end
%>

some features like "pagination","odd-even style","column sortable with correct sort-type" supported,and we can imagine more features like "export to excel","Globalization" to be added to "table_for" helper. so only open some options like :sortable=>false,we keep the code clean,consistent and maintainable. (like j2ee's displaytag?)

for it's used in my company,I am sorry not able to share the code to public.

let's enjoy blocks in view :)


16. Clint Moore Nov 25, 2007 at 14:54

Sorry... completely off topic.

If you listen very very closely you can hear frogs in the background. I can't help but imagine that you live on a bijou ala Happy Gilmore or something busting out awesome rails nuggets of smart from your two room shack.


17. space Dec 10, 2007 at 02:17

Is it possible to do something like:

<% my_box do |box| %>
  <% box.head do %>
     ...
  <% end %>
  <% box.content do %>
     ...
  <% end %>
<% end %>

As you see its going to wrap some HTML for a rounded box.

I tried for several hours to find a solution. The main problem is that i cant capture the contents of the block.call(some_function) method. It always outputs everything to the template immediatly.

Is there a way to it?


18. Tobi Jan 26, 2008 at 02:21

Thanks!


19. Georg Ledermann Feb 17, 2008 at 03:31

As in the comment from "space" mentioned, it's a bit complicated to build helper method for multiple wrapped tags. I found, that with HAML this task is very simple, because you get the helper methods "open" and "puts".

I have written a blog entry about this:
http://www.dipl-wirt-inf.de/2008/02/17/elegante-block-helper-mit-haml/

(german language, but you will get point with the code examples).

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player