Topic: blocks, yield

i have a helper

  def unordered_list_tree(tree, parent_id=nil)
    ret = "\n<ul>"
    tree.each do |node|
      if node.parent_id == parent_id
        ret += "\n\t<li>"
        ret += yield node
        ret += unordered_list_tree(tree, node.id) { |n| yield n } unless node.children.empty?
        ret += "\t</li>\n"
      end
    end
    ret += "</ul>\n"
  end

and in views i write

<%= unordered_list_tree(@categories) do |category|
    (link_to category.name, :action => 'show') + " " +
    (link_to 'Up',   {:action => 'move_up',   :id => category}, {:class => 'move-up'}  unless category.first?).to_s + " " +
    (link_to 'Down', {:action => 'move_down', :id => category}, {:class => 'move-down'} unless category.last?).to_s
  end
%>

is it possible to write something like this ?

<% unordered_list_tree(@categories) do |category| %>
  Hello, ...
  <%= link_to category.name, :action => 'show') %>
  <%= link_to 'Up',   {:action => 'move_up',   :id => category}, {:class => 'move-up'}  unless category.first? %>
  <%= link_to 'Down', {:action => 'move_down', :id => category}, {:class => 'move-down'} unless category.last? %>
<% end %>

Re: blocks, yield

Yes, there are a few built in ruby helpers that do this type of block syntax (such as form_for). It behaves a little strangely though.

From my understanding, when calling "yield" with this kind of block, the output isn't returned from the yield, instead it is output directly as the page content. This means you can't put the output into a variable in the helper method.

How do you output something before/after the block then? By using the concat method. Here's the end result.

  def unordered_list_tree(tree, parent_id=nil)
    concat("\n<ul>")
    tree.each do |node|
      if node.parent_id == parent_id
        concat("\n\t<li>")
        yield node
        # try it without this line first, you'll probably have to rework this because the result of the yield
        # isn't returned and therefore cannot be passed to another block AFAIK
        #unordered_list_tree(tree, node.id) { |n| yield n } unless node.children.empty?
        # you may be able to do this if you specify &block as an incoming parameter at the top of this function:
        # unordered_list_tree(tree, node.id, &block)
        concat("\t</li>\n")
      end
    end
    concat("</ul>\n")
  end

Does that work?

Railscasts - Free Ruby on Rails Screencasts