Improved BetterNestedSet Plugin

First the database migration used in all examples (using Rails 2.0 sexy migrations):

Please note that the left and right columns are named in such a way that they will not conflict with database reserved words commonly used in join statements.

Then the code:

This code works – but works slowly and yields horrific SQL. The reason it’s slow and horrific is because you need to hit each node in the tree to test for it’s number of children. This is less than ideal especially if you need to do this regularly (or on a tree with hundreds of nodes) – which leads us to the next iteration:

This works much better and is far more efficient. Each call to the class method makes a single query to the database. The reason the we can do this is because of the way nested sets work. A good explaination of this can be found in the BetterNestedSet README:

You can also check out additional nested set explanation in an article titled “A Nested Set Implementation…” (paying special attention to the illustrations in section #3).

Going back to our example, there’s one more thing we can to do make this one step better – move our methods into the plugin implementation. This makes sense as our class methods are not directly related to our application logic and pertain mainly to nested set behavior.

You can add a version of our methods to the nested set plugin by adding to the ClassMethods module in better_nested_set.rb in the lib folder of the BetterNestedSet plugin with the following:

Or if you’re savvy you can just apply the patch I created that includes these methods along with documentation and tests:

  • download the patch
  • move the patch to the root of your BetterNestedSet plugin
  • patch -p0 < leaves_and_parents_class_methods.patch

I’ve also added the patch as an enhancement to the BetterNestedSet trac.

On a recent project when I was using the BetterNestedSet plugin to manage a large hierarchal set of data, I encountered a problem that required me to find all of the items in a nested set that had children and those that didn’t. In nested set terms I wanted: all ‘parent’ nodes and all ‘leaf’ nodes that exist within the ‘tree’.

If you want to do this through the current BetterNestedSet interface you might be tempted to do something like this: