module SymetrieCom::Acts::NestedSet::ClassMethods

This module provides an enhanced acts_as_nested_set mixin for ActiveRecord. Please see the README for background information, examples, and tips on usage.

Public Instance Methods

acts_as_nested_set(options = {}) click to toggle source

Configuration options are:

  • dependent - behaviour for cascading destroy operations (default: :delete_all)

  • parent_column - Column name for the parent/child foreign key (default: parent_id).

  • left_column - Column name for the left index (default: lft).

  • right_column - Column name for the right index (default: rgt). NOTE: Don’t use left and right, since these are reserved database words.

  • scope - Restricts what is to be considered a tree. Given a symbol, it’ll attach “_id” (if it isn’t there already) and use that as the foreign key restriction. It’s also possible to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. Example: acts_as_nested_set :scope => 'tree_id = #{tree_id} AND completed = 0'

  • text_column - Column name for the title field (optional). Used as default in the {your-class}_options_for_select helper method. If empty, will use the first string field of your model class.

# File lib/symetrie_com/acts_as_better_nested_set.rb, line 24
        def acts_as_nested_set(options = {})          
          
          extend(SingletonMethods) unless respond_to?(:find_in_nestedset)
          
          options[:scope] = "#{options[:scope]}_id".intern if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
          
          write_inheritable_attribute(:acts_as_nested_set_options,
             { :parent_column  => (options[:parent_column] || 'parent_id'),
               :left_column    => (options[:left_column]   || 'lft'),
               :right_column   => (options[:right_column]  || 'rgt'),
               :scope          => (options[:scope] || '1 = 1'),
               :text_column    => (options[:text_column] || columns.collect{|c| (c.type == :string) ? c.name : nil }.compact.first),
               :class          => self, # for single-table inheritance
               :dependent      => (options[:dependent] || :delete_all) # accepts :delete_all and :destroy
              } )
          
          class_inheritable_reader :acts_as_nested_set_options
          
          base_set_class.class_inheritable_accessor :acts_as_nested_set_scope_enabled
          base_set_class.acts_as_nested_set_scope_enabled = true
          
          if acts_as_nested_set_options[:scope].is_a?(Symbol)
            scope_condition_method = %(
              def scope_condition
                if #{acts_as_nested_set_options[:scope].to_s}.nil?
                  self.class.use_scope_condition? ? "#{table_name}.#{acts_as_nested_set_options[:scope].to_s} IS NULL" : "(1 = 1)"
                else
                  self.class.use_scope_condition? ? "#{table_name}.#{acts_as_nested_set_options[:scope].to_s} = \#{#{acts_as_nested_set_options[:scope].to_s}}" : "(1 = 1)"
                end
              end
            )
          else
            scope_condition_method = "def scope_condition(); self.class.use_scope_condition? ? \"#{acts_as_nested_set_options[:scope]}\" : \"(1 = 1)\"; end"
          end
          
          # skip recursive destroy calls
          attr_accessor  :skip_before_destroy
          
          # no bulk assignment
          attr_protected  acts_as_nested_set_options[:left_column].intern,
                          acts_as_nested_set_options[:right_column].intern,
                          acts_as_nested_set_options[:parent_column].intern
          # no assignment to structure fields
          class_eval <<-EOV
            before_create :set_left_right
            before_destroy :destroy_descendants
            include SymetrieCom::Acts::NestedSet::InstanceMethods
          
            def #{acts_as_nested_set_options[:left_column]}=(x)
              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:left_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
            end
            def #{acts_as_nested_set_options[:right_column]}=(x)
              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:right_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
            end
            def #{acts_as_nested_set_options[:parent_column]}=(x)
              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:parent_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
            end
            #{scope_condition_method}
          EOV
        end