Skip to content

Instantly share code, notes, and snippets.

@vinnycrazzy
Forked from maxivak/__readme.md
Created August 12, 2021 01:30
Show Gist options
  • Save vinnycrazzy/ca62c1f350a14262cdd4e29874f917d4 to your computer and use it in GitHub Desktop.
Save vinnycrazzy/ca62c1f350a14262cdd4e29874f917d4 to your computer and use it in GitHub Desktop.
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