Module: SymetrieCom::Acts::NestedSet::ClassMethods

Defined in:
lib/better_nested_set.rb

Overview

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

Defined Under Namespace

Modules: SingletonMethods

Instance Method Summary collapse

Instance Method Details

#acts_as_nested_set(options = {}) ⇒ Object

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.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
# File 'lib/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