Turn an acts_as_tree structure into a select drop-down.

by Rabbit

This is probably the easiest way to turn Rails’ acts_as_tree structure into a select field:

HTML:

<select name="category_id">
  <%= expand_tree_into_select_field(Category.top) %>
</select>

Ruby helper:

def expand_tree_into_select_field(categories)
  returning(String.new) do |html|
    categories.each do |category|
      html << %{<option value="#{ category.id }">#{ '&nbsp;&nbsp;&nbsp;' * category.ancestors.size }#{ category.name }</option>}
      html << expand_tree_into_select_field(category.children) if category.has_children?
    end
  end
end

The Category.top method is simply:

def self.top
  find(:all, :conditions => [ 'parent_id IS NULL' ])
end

Finally, your Category class should implement has_children?:

def has_children?
  children.size > 0
end

That last bit is, of course, optional. You could easily write category.children.size > 0, but that’s not very object-oriented now, is it?

Enjoy!