Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Tree with ancestry. Rails

Contents:

  • show full path for the item
  • show tree in ol li
  • show tree in dropdown select

Show full path for item

  • one item

  • list of items

show full path for each item


# controller
@items = Category.where(..).all

# cache categories - all categories by ids
@all_categories_hash = Category.unscoped.all.inject({}){|res, elem| res[elem.id] = elem; res }


# view

- @items.each do |item|
    %h3= item.title
    path: 
    = item.ancestor_ids.map{|x| @all_categories_hash[x].title}.join(' / ')

Show tree for ancestry in Rails

Our model is organized in tree using ancestry gem.

We want to show in view the full tree with nested elements (with ul, li) like that:

<ul>
  <li>
        Fruits
        <ul>
          <li>Apple</li>
          <li>Orange</li>
        </ul>
  </li>
  <li>
        Vegetables
        <ul>
          <li>Tomato</li>
          <li>Potato</li>
          <li>Cabbage</li>
        </ul>
  </li>
</ul>
   
  • model
class Category ..

end

  • Category has attribute 'title' which will be shown in a tree.

  • controller


def index
  @items_tree = Category.all.arrange
end

  • create a helper method
# app/helpers/application_helper.rb

  def render_nested_groups(groups)
    s = content_tag(:ul) do
      groups.map do |group, sub_groups|
        content_tag(:li, (group.title +  nested_groups(sub_groups)).html_safe)
      end.join.html_safe
    end
  end

  • view

Use helper to present tree in view:

# app/views/categories/index.html.haml

= nested_groups(@items_tree)

Show tree in dropdown select

  • controller
  def edit
    @categories = collection_for_parent_select
  end
  

  def collection_for_parent_select
    @categories = ancestry_options(Category.unscoped.arrange(:order => 'name')) {|i| "#{'-' * i.depth} #{i.name}" }
  end

  def ancestry_options(items)
    result = []
    items.map do |item, sub_items|
      result << [yield(item), item.id]
      #this is a recursive call:
      result += ancestry_options(sub_items) {|i| "#{'-' * i.depth} #{i.name}" }
    end
    result
  end

  • form
= f.input :parent_id, :as => :select, :collection => @categories
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.