module Resort::Sortable::InstanceMethods

Instance methods to use.

Public Instance Methods

append_to(another) click to toggle source

Puts the object right after another object in the list.

# File lib/resort.rb, line 175
def append_to(another)
  self.class.transaction do
    self.lock!
    return if another.next_id == id
    another.lock!
    delete_from_list
    if self.next_id or (another && another.next_id)
      raise(ActiveRecord::RecordNotSaved) unless self.update_attribute(:next_id, another.next_id)
    end
    if another
      raise(ActiveRecord::RecordNotSaved) unless another.update_attribute(:next_id, self.id)
    end
  end
end
include_in_list!() click to toggle source

Includes the object in the linked list.

If there are no other objects, it prepends the object so that it is in the first position. Otherwise, it appends it to the end of the empty list.

# File lib/resort.rb, line 143
def include_in_list!
  self.class.transaction do
    self.lock!
    _siblings.count > 0 ? last!\
                        : prepend
  end
end
prepend() click to toggle source

Puts the object in the first position of the list.

# File lib/resort.rb, line 152
def prepend
  self.class.transaction do
    self.lock!
    return if first?
    if _siblings.count > 0
      delete_from_list
      old_first = _siblings.first_in_order
      raise(ActiveRecord::RecordNotSaved) unless self.update_attribute(:next_id, old_first.id)
      raise(ActiveRecord::RecordNotSaved) unless old_first.update_attribute(:first, false)
    end
    raise(ActiveRecord::RecordNotSaved) unless self.update_attribute(:first, true)
  end
end
push() click to toggle source

Puts the object in the last position of the list.

# File lib/resort.rb, line 167
def push
  self.class.transaction do
    self.lock!
    self.append_to(_siblings.last_in_order) unless last?
  end
end
siblings() click to toggle source

Default definition of siblings, i.e. every instance of the model.

Can be overriden to specify a different scope for the siblings. For example, if we wanted to limit a products tree inside a ProductLine scope, we would do the following:

class Product < ActiveRecord::Base
  belongs_to :product_line

  resort!

  def siblings
    self.product_line.products
  end

This way, every product line is an independent tree of sortable products.

@return [ActiveRecord::Relation] the element’s siblings relation.

# File lib/resort.rb, line 135
def siblings
  self.class.scoped
end

Private Instance Methods

_siblings() click to toggle source
# File lib/resort.rb, line 220
def _siblings
  table = self.class.arel_table
  siblings.where(table[:id].not_eq(self.id))
end
delete_from_list() click to toggle source
# File lib/resort.rb, line 192
def delete_from_list
  if first? && self.next
    self.next.lock!
    raise(ActiveRecord::RecordNotSaved) unless self.next.update_attribute(:first, true)
  elsif self.previous
    self.previous.lock!
    p = self.previous
    self.previous = nil unless frozen?
    raise(ActiveRecord::RecordNotSaved) unless p.update_attribute(:next_id, self.next_id)
  end
  unless frozen?
    self.first = false 
    self.next = nil 
    save!
  end
end
last!() click to toggle source
# File lib/resort.rb, line 213
def last!
  self.class.transaction do
    self.lock!
    raise(ActiveRecord::RecordNotSaved) unless _siblings.last_in_order.update_attribute(:next_id, self.id)
  end
end
last?() click to toggle source
# File lib/resort.rb, line 209
def last?
  !self.first && !self.next_id
end