Module: CollectiveIdea::Acts::NestedSet::SingletonMethods

Defined in:
lib/awesome_nested_set.rb

Overview

This acts provides Nested Set functionality. Nested Set is a smart way to implement an ordered tree, with the added feature that you can select the children and all of their descendants with a single query. The drawback is that insertion or move need some complex sql queries. But everything is done here by this module!

Nested sets are appropriate each time you want either an orderd tree (menus, commercial categories) or an efficient way of querying big trees (threaded posts).

API

Methods names are aligned with acts_as_tree as much as possible, to make replacment from one by another easier, except for the creation:

in acts_as_tree:

item.children.create(:name => "child1")

in acts_as_nested_set:

# adds a new item at the "end" of the tree, i.e. with child.left = max(tree.right)+1
child = MyClass.new(:name => "child1")
child.save
# now move the item to its right place
child.move_to_child_of my_item

You can pass an id or an object to:

  • #move_to_child_of

  • #move_to_right_of

  • #move_to_left_of

Instance Method Summary collapse

Instance Method Details

#acts_as_nested_set(options = {}) ⇒ Object

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”

  • :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.

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



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/awesome_nested_set.rb', line 54

def acts_as_nested_set(options = {})
  options = {
    :parent_column => 'parent_id',
    :left_column => 'lft',
    :right_column => 'rgt',
    :dependent => :delete_all, # or :destroy
  }.merge(options)
  
  if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
    options[:scope] = "#{options[:scope]}_id".intern
  end

  write_inheritable_attribute :acts_as_nested_set_options, options
  class_inheritable_reader :acts_as_nested_set_options
  
  include Comparable
  include Columns
  include InstanceMethods
  extend Columns
  extend ClassMethods

  # no bulk assignment
  attr_protected  left_column_name.intern,
                  right_column_name.intern
                  
  before_create :set_default_left_and_right
  before_destroy :prune_from_tree
                  
  # no assignment to structure fields
  [left_column_name, right_column_name].each do |column|
    module_eval <<-"end_eval", __FILE__, __LINE__
      def #{column}=(x)
        raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
      end
    end_eval
  end
  
  named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name
  named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name
  if self.respond_to?(:define_callbacks)
    define_callbacks("before_move", "after_move")              
  end

  
end