Skip to content

Instantly share code, notes, and snippets.

@tabishiqbal
Forked from maxivak/__readme.md
Created April 30, 2020 05:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tabishiqbal/8d48b89b15061a7b67c1894b28ac65dd to your computer and use it in GitHub Desktop.
Save tabishiqbal/8d48b89b15061a7b67c1894b28ac65dd 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