module BeyondAlbert::Acts::TextBasedNestedSet::Model

Public Instance Methods

ancestors() click to toggle source
# File lib/text_based_nested_set/model.rb, line 147
def ancestors
  parent_ids = self.path.split('/').select {|v| v != "" && v != "0"}
  current_class.where(id: parent_ids).order("LENGTH(path) ASC")
end
check_position() click to toggle source
# File lib/text_based_nested_set/model.rb, line 215
def check_position
  logger = Logger.new(STDOUT)
  if self.children.size != 0
    if self.children.size == self.children.last.position + 1
      self.children.each do |c|
        c.check_position
      end
    else
      logger.info("position not correct, node id: #{self.id}")
      return false
    end
  end
  return true
end
children() click to toggle source
# File lib/text_based_nested_set/model.rb, line 156
def children
  children_path = self.path + self.id.to_s + '/'
  current_class.where(path: children_path).order('position')
end
descendants() click to toggle source
# File lib/text_based_nested_set/model.rb, line 161
def descendants
  descendants_path = self.path + self.id.to_s + '/%'
  current_class.where("path LIKE ?", descendants_path).order("LENGTH(path) ASC, position ASC")
end
left_sibling() click to toggle source
# File lib/text_based_nested_set/model.rb, line 179
def left_sibling
  left_siblings = current_class.where(path: self.path, position: self.position - 1 )
  if left_siblings.empty?
    nil
  else
    left_siblings.first
  end
end
move_to_child_of(target) click to toggle source
# File lib/text_based_nested_set/model.rb, line 116
def move_to_child_of(target)
  in_tenacious_transaction do
    descendants = self.descendants

    # set old siblings' position
    self.siblings.each do |s|
      if s.position > self.position
        s.position -= 1
        s.save!
      end
    end

    # set self attributes
    self.update(path: target.path + target.id.to_s + '/', parent_id: target.id, position: target.children.size)

    # set descendants' path
    descendants.each do |d|
      d.path = d.parent.path + d.parent_id.to_s + '/'
      d.save!
    end
  end
end
move_to_left_of(target) click to toggle source
# File lib/text_based_nested_set/model.rb, line 53
def move_to_left_of(target)
  in_tenacious_transaction do
    descendants = self.descendants

    # set new siblings's position
    target.self_and_siblings.each do |s|
      if s.position >= target.position
        s.position += 1
        s.save!
      end
    end
    target.reload

    # set old siblings's position
    self.siblings.each do |s|
      if s.position > self.position
        s.position -= 1
        s.save!
      end
    end

    # set self attributes
    self.update(path: target.path, parent_id: target.parent_id, position: target.position - 1)

    # set descendants' path
    descendants.each do |d|
      d.path = d.parent.path + d.parent_id.to_s + '/'
      d.save!
    end
  end
end
move_to_right_of(target) click to toggle source
# File lib/text_based_nested_set/model.rb, line 85
def move_to_right_of(target)
  in_tenacious_transaction do
    descendants = self.descendants

    # set new siblings' position
    target.self_and_siblings.each do |s|
      if s.position > target.position
        s.position += 1
        s.save!
      end
    end

    # set old siblings' position
    self.siblings.each do |s|
      if s.position > self.position
        s.position -= 1
        s.save!
      end
    end

    # set self attributes
    self.update(path: target.path, parent_id: target.parent_id, position: target.position + 1)

    # set descendants' path
    descendants.each do |d|
      d.path = d.parent.path + d.parent_id.to_s + '/'
      d.save!
    end
  end
end
move_to_root() click to toggle source
# File lib/text_based_nested_set/model.rb, line 30
def move_to_root
  in_tenacious_transaction do
    # reset siblings' position
    self.siblings.each do |s|
      if s.position > self.position
        s.position -= 1
        s.save!
      end
    end

    descendants = self.descendants

    self.update(parent_id: 0, path: '/0/', position: 0)

    # reset descendants' path
    descendants.each do |d|
      d.path = d.parent.path + d.parent_id.to_s + '/'
      d.save!
    end

  end
end
parent() click to toggle source
# File lib/text_based_nested_set/model.rb, line 139
def parent
  if self.root?
    nil
  else
    current_class.find(self.parent_id)
  end
end
rebuild() click to toggle source
# File lib/text_based_nested_set/model.rb, line 200
def rebuild
  in_tenacious_transaction do
    children = current_class.where(parent_id: self.id)
    if self.parent_id == 0
      self.update!(path: '/0/')
    end
    unless children.empty?
      children.each.with_index do |c, index|
        c.update(path: self.path + self.id.to_s + '/', position: index)
        c.rebuild
      end
    end
  end
end
right_sibling() click to toggle source
# File lib/text_based_nested_set/model.rb, line 170
def right_sibling
  right_siblings = current_class.where(path: self.path, position: self.position + 1)
  if right_siblings.empty?
    nil
  else
    right_siblings.first
  end
end
root?() click to toggle source
# File lib/text_based_nested_set/model.rb, line 196
def root?
  self.parent_id == 0
end
self_and_ancestors() click to toggle source
# File lib/text_based_nested_set/model.rb, line 152
def self_and_ancestors
  ancestors << self
end
self_and_descendants() click to toggle source
# File lib/text_based_nested_set/model.rb, line 166
def self_and_descendants
  descendants.unshift(self)
end
self_and_siblings() click to toggle source
# File lib/text_based_nested_set/model.rb, line 192
def self_and_siblings
  current_class.where(path: self.path)
end
siblings() click to toggle source
# File lib/text_based_nested_set/model.rb, line 188
def siblings
  current_class.where(path: self.path).select {|o| o.id != self.id}
end

Private Instance Methods

current_class() click to toggle source
# File lib/text_based_nested_set/model.rb, line 248
def current_class
  self.class.base_class
end
destroy_descendants() click to toggle source
# File lib/text_based_nested_set/model.rb, line 252
def destroy_descendants
  self.descendants.destroy_all
end
in_tenacious_transaction(&block) click to toggle source
# File lib/text_based_nested_set/model.rb, line 232
def in_tenacious_transaction(&block)
  logger = Logger.new(STDOUT)
  retry_count = 0
  begin
    transaction(&block)
  rescue ActiveRecord::StatementInvalid => error
    raise unless connection.open_transactions.zero?
    raise unless error.message =~ /Deadlock found when trying to get lock|Lock wait timeout exceeded/
    raise unless retry_count < 10
    retry_count += 1
    logger.info "Deadlock detected on retry #{retry_count}, restarting transaction"
    sleep(rand(retry_count)*0.1) # Aloha protocol
    retry
  end
end