module CollectiveIdea::Acts::NestedSet
def acts_as_nested_set(options = {})
CollectiveIdea::Acts::NestedSet::Model for a list of instance methods added
See CollectiveIdea::Acts::NestedSet::Model::ClassMethods for a list of class methods and
Example: acts_as_nested_set :order_column => :position
* +:order_column+ on which column to do sorting, by default it is the left_column_name
Example: acts_as_nested_set :counter_cache => :children_count
defaults to false.
* +:counter_cache+ adds a counter cache for the number of children.
without calling their destroy method.
method. If set to :delete_all (default), all the child objects are deleted
child objects are destroyed alongside this object by calling their destroy
* +:dependent+ - behavior for cascading destroy. If set to :destroy, all the
Example: acts_as_nested_set :scope => [:notable_id, :notable_type]
can also pass an array to scope by multiple attributes.
(if it hasn't been already) and use that as the foreign key restriction. You
* +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id"
* +:depth_column+ - column name for the depth data, default "depth"
* +:right_column+ - column name for right boundary data, default "rgt"
* +:left_column+ - column name for left boundary data, default "lft"
* +:primary_column+ - specifies the column name to use as the inverse of the parent column (default: id)
* +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id)
Configuration options are:
def acts_as_nested_set(options = {}) acts_as_nested_set_parse_options! options include Model include Columns extend Columns acts_as_nested_set_relate_parent! acts_as_nested_set_relate_children! attr_accessor :skip_before_destroy acts_as_nested_set_prevent_assignment_to_reserved_columns! acts_as_nested_set_define_callbacks! end
def acts_as_nested_set_default_options
def acts_as_nested_set_default_options { :parent_column => 'parent_id', :primary_column => 'id', :left_column => 'lft', :right_column => 'rgt', :depth_column => 'depth', :dependent => :delete_all, # or :destroy :polymorphic => false, :counter_cache => false, :touch => false }.freeze end
def acts_as_nested_set_define_callbacks!
def acts_as_nested_set_define_callbacks! # on creation, set automatically lft and rgt to the end of the tree before_create :set_default_left_and_right before_save :store_new_parent after_save :move_to_new_parent, :set_depth! before_destroy :destroy_descendants define_model_callbacks :move end
def acts_as_nested_set_parse_options!(options)
def acts_as_nested_set_parse_options!(options) options = acts_as_nested_set_default_options.merge(options) if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ options[:scope] = "#{options[:scope]}_id".intern end class_attribute :acts_as_nested_set_options self.acts_as_nested_set_options = options end
def acts_as_nested_set_prevent_assignment_to_reserved_columns!
def acts_as_nested_set_prevent_assignment_to_reserved_columns! # no assignment to structure fields [left_column_name, right_column_name, depth_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 end
def acts_as_nested_set_relate_children!
def acts_as_nested_set_relate_children! has_many_children_options = { :class_name => self.base_class.to_s, :foreign_key => parent_column_name, :primary_key => primary_column_name, :inverse_of => (:parent unless acts_as_nested_set_options[:polymorphic]), } # Add callbacks, if they were supplied.. otherwise, we don't want them. [:before_add, :after_add, :before_remove, :after_remove].each do |ar_callback| has_many_children_options.update( ar_callback => acts_as_nested_set_options[ar_callback] ) if acts_as_nested_set_options[ar_callback] end has_many :children, -> { order(order_column_name) }, **has_many_children_options end
def acts_as_nested_set_relate_parent!
def acts_as_nested_set_relate_parent! options = { :class_name => self.base_class.to_s, :foreign_key => parent_column_name, :primary_key => primary_column_name, :counter_cache => acts_as_nested_set_options[:counter_cache], :inverse_of => (:children unless acts_as_nested_set_options[:polymorphic]), :touch => acts_as_nested_set_options[:touch] } options[:polymorphic] = true if acts_as_nested_set_options[:polymorphic] options[:optional] = true if ActiveRecord::VERSION::MAJOR >= 5 belongs_to :parent, **options end