Nested categories with rails gem Ancestry.

George Chkhvirkia
HackerNoon.com
3 min readOct 17, 2017

--

Imagine you dealing with project where you have categories, and products in those categories, clothes website as an example. You may have following tree of categories:

DB structure is very simple — id, parent_id, title for categories and category_id in products. Pretty straightforward, you can easily get parent and/or children of a category.

But you need to consider — if you select JEANS, it means you want JEANS + Straight JEANS + Skinny JEANS and so on. To achieve that you need selected category id, and ids of its children. Its easy to get them with rails, just write a small custom scope for it.

But what if children have their own children and tree is much deeper ? You will have to write advanced queries, joins, recursions to get ids of children on all levels. Or imagine you have selected last category, and you want to get all existing parents for it, or you want siblings of selected category (all items on the selected level, like Shirts, Jeans, …). By writing custom scopes and methods for all such cases, you will end up with huge and messy model pretty quickly.

One of the best tools to deal with nested categories is gem Ancestry (https://github.com/stefankroes/ancestry), with a lot of helper scopes and methods, especially for cases mentioned above.

Usage

Ancestry is very easy to understand and use.

Example project here: https://github.com/gioch/ancestry_test.git

  • Add gem ancestry to Gemfile.
  • Create model for categories (without parent_id or anything like that, ancestry will take care of it for us)
  • Generate migration to add ancestry field to categories:
  • Add `has_ancestry` to Categories model

Creating categories and subcategories

Its easy to create subcategories, you just need to specify parent on create:

Getting all children for selected category

Ancestry’s helpers are working like magic. Use method children to get subcategories, or child_ids to get only an array of ids of children:

But, as mentioned above, if tree is very deep, and you want all levels of children, use descendants instead:

Getting all parents of selected category

If you have selected last category in a tree, and you want to get all parents, use ancestors or ancestor_ids:

Getting products of specified category

Ancestry has a lot of other helpful methods.

Additional Resources

Check Ancestry’s github page here - https://github.com/stefankroes/ancestry

Check Railscast for ancestry — http://railscasts.com/episodes/262-trees-with-ancestry

--

--