first some background info: I have a blog application that has a comments table with the following columns: id parent_id post_id created_at body here''s my model: class Comment < ActiveRecord::Base belongs_to :post acts_as_tree :order => ''created_at'' def print_children (options={}) before = options[:before] ? options[:before] : '''' after = options[:after] ? options[:after] : '''' before_children = options[:before_children] ? options[:before_children] : '''' after_children = options[:after_children] ? options[:after_children] : '''' output = '''' for child in children output += before output += child.body if !child.children.empty? output += before_children output += child.print_children options output += after_children end output += after end return output end end the print_children method takes several options, for example, in my view it call it like: <ul> <% for comment in @comments %> <li> <%= comment.body %> <% if !comment.children.empty? %> <ul> <%= comment.print_children :before => ''<li>'', :after => ''</li>'', :before_children => ''<ul>'', :after_children => ''</ul>'' %> </ul> <% end %> </li> <% end %> </ul> @comments is an array of all the comments for the current post where parent_id is null (each of those potentially has a tree of comments beneath it) that will give me all the comments in nice nested lists. Now for the question. Is there a way to make something like this use a partial template, such that, for each comment, I could render a template, instead of passing several options to print_children? The way it works now, if i want to display more comment properties (for example, created_at, or in the future, the author) or if i wanted to format each comment in some odd way I have to change both my template AND my print_children method. -Dana
The solution is to use a recursive partial template, this keeps all the display code in view where it belongs. the model: class Comment < ActiveRecord::Base belongs_to :post acts_as_tree :order => ''created_at'' end the main template: <div class="comments"> <ul> <% for comment in @comments %> <%= render :partial => ''comment'', :locals => {:comment => comment} %> <% end %> </ul> </div> and the partial template (_comment.rhtml), notice how it renders itself: <li> <div> <%= comment.body %> </div> <% if !comment.children.empty? %> <ul> <% for comment in comment.children %> <%= render :partial => ''comment'', :locals => {:comment => comment } %> <% end %> </ul> <% end %> </li> -- Posted via http://www.ruby-forum.com/.
Dana wrote: I can''t believe I wrote the same kind of code today. I chose to use the :collection member of the options hash to let Rails iterate the collections. This just happens to be my application -- a menu tree -- but it looks pretty much like any other kind of tree:) BTW: This can be also accomplished very nicely with Builder::XmlMarkup used in a simple recursion. template: <ul> <%= render :partial => ''menu_list'', :collection => @menus %> </ul> partial: <li> <%= menu_list.menu_name %> <% if menu_list.has_children? -%> <ul> <%= render(:partial => ''menu_list'', :collection => menu_list.children) %> </ul> <% end -%> </li>> the main template: > > <div class="comments"> > <ul> > <% for comment in @comments %> > <%= render :partial => ''comment'', :locals => {:comment => comment} > %> > <% end %> > </ul> > </div> > > and the partial template (_comment.rhtml), notice how it renders itself: > > <li> > <div> > <%= comment.body %> > </div> > <% if !comment.children.empty? %> > <ul> > <% for comment in comment.children %> > <%= render :partial => ''comment'', :locals => {:comment => > comment } %> > <% end %> > </ul> > <% end %> > </li>-- Posted via http://www.ruby-forum.com/.