Skip to content
This repository

An awesome replacement for acts_as_nested_set and better_nested_set.


Build Status

Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is a replacement for acts_as_nested_set and BetterNestedSet, but more awesome.

Version 2 supports Rails 3. Gem versions prior to 2.0 support Rails 2.

What makes this so awesome?

This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support.

Code Climate


Add to your Gemfile:

gem 'awesome_nested_set'


To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id. The names of these fields are configurable. You can also have an optional field, depth:

class CreateCategories < ActiveRecord::Migration
  def self.up
    create_table :categories do |t|
      t.string :name
      t.integer :parent_id
      t.integer :lft
      t.integer :rgt
      t.integer :depth # this is optional.

  def self.down
    drop_table :categories

Enable the nested set functionality by declaring acts_as_nested_set on your model

class Category < ActiveRecord::Base

Run rake rdoc to generate the API docs and see CollectiveIdea::Acts::NestedSet for more information.


You can pass various options to acts_as_nested_set macro. Configuration options are:

  • parent_column: specifies the column name to use for keeping the position integer (default: parent_id)
  • left_column: column name for left boundry data (default: lft)
  • right_column: column name for right boundry data (default: rgt)
  • depth_column: column name for the depth data default (default: depth)
  • scope: restricts what is to be considered a list. Given a symbol, it'll attach “_id” (if it hasn't been already) and use that as the foreign key restriction. You can also pass an array to scope by multiple attributes. Example: acts_as_nested_set :scope => [:notable_id, :notable_type]
  • dependent: behavior for cascading destroy. If set to :destroy, all the child objects are destroyed alongside this object by calling their destroy method. If set to :delete_all (default), all the child objects are deleted without calling their destroy method.
  • counter_cache: adds a counter cache for the number of children. defaults to false. Example: acts_as_nested_set :counter_cache => :children_count
  • order_column: on which column to do sorting, by default it is the left_column_name. Example: acts_as_nested_set :order_column => :position

See CollectiveIdea::Acts::NestedSet::Model::ClassMethods for a list of class methods and CollectiveIdea::Acts::NestedSet::Model for a list of instance methods added to acts_as_nested_set models


It is highly recommended that you add an index to the rgt column on your models. Every insertion requires finding the next rgt value to use and this can be slow for large tables without an index. It is probably best to index the other fields as well (parent_id, lft, depth).


There are three callbacks called when moving a node: before_move, after_move and around_move.

class Category < ActiveRecord::Base

  after_move :rebuild_slug
  around_move :da_fancy_things_around


  def rebuild_slug
    # do whatever

  def da_fancy_things_around
    # do something...
    yield # actually moves
    # do something else...

Beside this there are also hooks to act on the newly added or removed children.

class Category < ActiveRecord::Base
  acts_as_nested_set  :before_add     => :do_before_add_stuff,
                      :after_add      => :do_after_add_stuff,
                      :before_remove  => :do_before_remove_stuff,
                      :after_remove   => :do_after_remove_stuff


  def do_before_add_stuff(child_node)
    # do whatever with the child

  def do_after_add_stuff(child_node)
    # do whatever with the child

  def do_before_remove_stuff(child_node)
    # do whatever with the child

  def do_after_remove_stuff(child_node)
    # do whatever with the child

Protecting attributes from mass assignment

It's generally best to "whitelist" the attributes that can be used in mass assignment:

class Category < ActiveRecord::Base
  attr_accessible :name, :parent_id

If for some reason that is not possible, you will probably want to protect the lft and rgt attributes:

class Category < ActiveRecord::Base
  attr_protected :lft, :rgt

Conversion from other trees

Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run:


Your tree will be converted to a valid nested set. Awesome!

View Helper

The view helper is called #nested_set_options.

Example usage:

<%= :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{}" } %>

<%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{}" } ) %>

See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.


You can learn more about nested sets at:

How to contribute

Please see the 'Contributing' document.

Copyright © 2008 - 2013 Collective Idea, released under the MIT license

Something went wrong with that request. Please try again.