Module: ActiveRecord::Acts::NestedSet::InstanceMethods

Defined in:
lib/active_record/acts/nested_set.rb

Instance Method Summary collapse

Instance Method Details

#add_child(child) ⇒ Object

Adds a child to this object in the tree. If this object hasn't been initialized, it gets set up as a root node. Otherwise, this method will update all of the other elements in the tree and shift them to the right, keeping everything balanced.


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/active_record/acts/nested_set.rb', line 139

def add_child( child )
  self.reload
  child.reload

  if child.root?
    raise "Adding sub-tree isn\'t currently supported"
  else
    if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) )
      # Looks like we're now the root node!  Woo
      self[left_col_name] = 1
      self[right_col_name] = 4

      # What do to do about validation?
      return nil unless self.save

      child[parent_column] = self.id
      child[left_col_name] = 2
      child[right_col_name]= 3
      return child.save
    else
      # OK, we need to add and shift everything else to the right
      child[parent_column] = self.id
      right_bound = self[right_col_name]
      child[left_col_name] = right_bound
      child[right_col_name] = right_bound + 1
      self[right_col_name] += 2
      self.class.base_class.transaction {
        self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} + 2)",  "#{scope_condition} AND #{left_col_name} >= #{right_bound}" )
        self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} + 2)",  "#{scope_condition} AND #{right_col_name} >= #{right_bound}" )
        self.save
        child.save
      }
    end
  end
end

#all_childrenObject

Returns a set of all of its children and nested children


186
187
188
# File 'lib/active_record/acts/nested_set.rb', line 186

def all_children
  self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} > #{self[left_col_name]}) and (#{right_col_name} < #{self[right_col_name]})" )
end

#before_destroyObject

Prunes a branch off of the tree, shifting all of the elements on the right back to the left so the counts still work.


197
198
199
200
201
202
203
204
205
206
# File 'lib/active_record/acts/nested_set.rb', line 197

def before_destroy
  return if self[right_col_name].nil? || self[left_col_name].nil?
  dif = self[right_col_name] - self[left_col_name] + 1

  self.class.base_class.transaction {
    self.class.base_class.delete_all( "#{scope_condition} and #{left_col_name} > #{self[left_col_name]} and #{right_col_name} < #{self[right_col_name]}" )
    self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} - #{dif})",  "#{scope_condition} AND #{left_col_name} >= #{self[right_col_name]}" )
    self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} - #{dif} )",  "#{scope_condition} AND #{right_col_name} >= #{self[right_col_name]}" )
  }
end

#child?Boolean

Returns true is this is a child node


125
126
127
128
# File 'lib/active_record/acts/nested_set.rb', line 125

def child?
  parent_id = self[parent_column]
  !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name])
end

#children_countObject

Returns the number of nested children of this object.


176
177
178
# File 'lib/active_record/acts/nested_set.rb', line 176

def children_count
  return (self[right_col_name] - self[left_col_name] - 1)/2
end

#direct_childrenObject

Returns a set of only this entry's immediate children


191
192
193
# File 'lib/active_record/acts/nested_set.rb', line 191

def direct_children
  self.class.base_class.find(:all, :conditions => "#{scope_condition} and #{parent_column} = #{self.id}", :order => left_col_name)
end

#full_setObject

Returns a set of itself and all of its nested children


181
182
183
# File 'lib/active_record/acts/nested_set.rb', line 181

def full_set
  self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} and #{self[right_col_name]})" )
end

#root?Boolean

Returns true is this is a root node.


119
120
121
122
# File 'lib/active_record/acts/nested_set.rb', line 119

def root?
  parent_id = self[parent_column]
  (parent_id == 0 || parent_id.nil?) && (self[left_col_name] == 1) && (self[right_col_name] > self[left_col_name])
end

#unknown?Boolean

Returns true if we have no idea what this is


131
132
133
# File 'lib/active_record/acts/nested_set.rb', line 131

def unknown?
  !root? && !child?
end