RubyLogo acts_as_tree est un petit plugin inclu dans rails permettant de donner un comportement en arbre des élements d'un model (voir son api), ce qui est très utile pour les catégories, entre autres.

Il n'y a en revanche rien de pré-fabriqué pour afficher ces lignes de la bonne façon, outre ceci qui se contente de l'afficher en liste HTML.

Il me fallait un <select> organisé de la même façon.

J'ai donc écrit le code suivant, qui est à placer dans vos helpers (app/helpers/application_helper.rb afin d'être actif partout), qui vous permettra, dans un formulaire, d'utiliser ceci :

<% form_for :post, :url => posts_path do |f| %>
<%= f.select :category_id, options_for_categories(Category.find(:all)) %>
<% end %>

... ce qui vous donnera quelque-chose comme cela :

<select id="post_category_id" name="post[category_id]">
<option value="5">Linux</option>
<option value="6">--ubuntu</option>
<option value="9">----kubuntu</option>
<option value="10">----xubuntu</option>
<option value="7">--redhat</option>
<option value="8">----fedora</option>
<option value="12">BSD</option>
<option value="14">--FreeBSD</option>
</select>

Le code à insérer dans votre helper est le suivant :

 def options_for_categories(categories)
   ret = []
   for category in categories
     if category.parent_id == 0
       ret << [category.title, category.id]
       ret += options_for_subcategories(category)
     end
   end
   ret
 end

 def options_for_subcategories(category, level='')
   ret = []
   if category.children.size > 0
     level += '--'
     category.children.each do |subcat|
       ret << [ level + subcat.title, subcat.id]
       if subcat.children.size > 0
         ret += options_for_subcategories(subcat, level)
       end
     end
   end
   ret
 end

Enjoy.