module ActiveRecord::Acts::List::InstanceMethods

All the methods available to a record that has had acts_as_list specified. Each method works by assuming the object to be the item in the list, so chapter.move_lower would move that chapter lower in the list of all chapters. Likewise, chapter.first? would return true if that chapter is the first in the list of all chapters.

Public Instance Methods

decrement_position() click to toggle source

Decrease the position of this item without adjusting the rest of the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 198
def decrement_position
  return unless in_list?
  set_list_position(self.send(position_column).to_i - 1)
end
default_position() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 264
def default_position
  acts_as_list_class.columns_hash[position_column.to_s].default
end
default_position?() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 268
def default_position?
  default_position == send(position_column)
end
first?() click to toggle source

Return true if this object is the first in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 204
def first?
  return false unless in_list?
  self.send(position_column) == acts_as_list_top
end
higher_item() click to toggle source

Return the next higher item in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 216
def higher_item
  return nil unless in_list?
  acts_as_list_class.unscoped.
    where("#{scope_condition} AND #{position_column} < #{(send(position_column).to_i).to_s}").
    order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
end
higher_items(limit=nil) click to toggle source

Return the next n higher items in the list selects all higher items by default

# File lib/acts_as_list/active_record/acts/list.rb, line 225
def higher_items(limit=nil)
  limit ||= acts_as_list_list.count
  position_value = send(position_column)
  acts_as_list_list.
    where("#{position_column} < ?", position_value).
    where("#{position_column} >= ?", position_value - limit).
    limit(limit).
    order("#{acts_as_list_class.table_name}.#{position_column} ASC")
end
in_list?() click to toggle source

Test if this record is in a list

# File lib/acts_as_list/active_record/acts/list.rb, line 256
def in_list?
  !not_in_list?
end
increment_position() click to toggle source

Increase the position of this item without adjusting the rest of the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 192
def increment_position
  return unless in_list?
  set_list_position(self.send(position_column).to_i + 1)
end
insert_at(position = acts_as_list_top) click to toggle source

Insert the item at the given position (defaults to the top position of 1).

# File lib/acts_as_list/active_record/acts/list.rb, line 133
def insert_at(position = acts_as_list_top)
  insert_at_position(position)
end
last?() click to toggle source

Return true if this object is the last in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 210
def last?
  return false unless in_list?
  self.send(position_column) == bottom_position_in_list
end
lower_item() click to toggle source

Return the next lower item in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 236
def lower_item
  return nil unless in_list?
  acts_as_list_class.unscoped.
    where("#{scope_condition} AND #{position_column} > #{(send(position_column).to_i).to_s}").
    order("#{acts_as_list_class.table_name}.#{position_column} ASC").first
end
lower_items(limit=nil) click to toggle source

Return the next n lower items in the list selects all lower items by default

# File lib/acts_as_list/active_record/acts/list.rb, line 245
def lower_items(limit=nil)
  limit ||= acts_as_list_list.count
  position_value = send(position_column)
  acts_as_list_list.
    where("#{position_column} > ?", position_value).
    where("#{position_column} <= ?", position_value + limit).
    limit(limit).
    order("#{acts_as_list_class.table_name}.#{position_column} ASC")
end
move_higher() click to toggle source

Swap positions with the next higher item, if one exists.

# File lib/acts_as_list/active_record/acts/list.rb, line 148
def move_higher
  return unless higher_item

  acts_as_list_class.transaction do
    higher_item.increment_position
    decrement_position
  end
end
move_lower() click to toggle source

Swap positions with the next lower item, if one exists.

# File lib/acts_as_list/active_record/acts/list.rb, line 138
def move_lower
  return unless lower_item

  acts_as_list_class.transaction do
    lower_item.decrement_position
    increment_position
  end
end
move_to_bottom() click to toggle source

Move to the bottom of the list. If the item is already in the list, the items below it have their position adjusted accordingly.

# File lib/acts_as_list/active_record/acts/list.rb, line 159
def move_to_bottom
  return unless in_list?
  acts_as_list_class.transaction do
    decrement_positions_on_lower_items
    assume_bottom_position
  end
end
move_to_top() click to toggle source

Move to the top of the list. If the item is already in the list, the items above it have their position adjusted accordingly.

# File lib/acts_as_list/active_record/acts/list.rb, line 169
def move_to_top
  return unless in_list?
  acts_as_list_class.transaction do
    increment_positions_on_higher_items
    assume_top_position
  end
end
move_within_scope(scope_id) click to toggle source

Move the item within scope

# File lib/acts_as_list/active_record/acts/list.rb, line 186
def move_within_scope(scope_id)
  send("#{scope_name}=", scope_id)
  save!
end
not_in_list?() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 260
def not_in_list?
  send(position_column).nil?
end
remove_from_list() click to toggle source

Removes the item from the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 178
def remove_from_list
  if in_list?
    decrement_positions_on_lower_items
    set_list_position(nil)
  end
end
set_list_position(new_position) click to toggle source

Sets the new position and saves it

# File lib/acts_as_list/active_record/acts/list.rb, line 273
def set_list_position(new_position)
  send("#{position_column}=", new_position)
  save!
end

Private Instance Methods

acts_as_list_list() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 279
def acts_as_list_list
  acts_as_list_class.unscoped.
    where(scope_condition)
end
add_to_list_bottom() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 289
def add_to_list_bottom
  if not_in_list? || default_position?
    self[position_column] = bottom_position_in_list.to_i + 1
  else
    increment_positions_on_lower_items(self[position_column])
  end
end
add_to_list_top() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 284
def add_to_list_top
  increment_positions_on_all_items
  self[position_column] = acts_as_list_top
end
assume_bottom_position() click to toggle source

Forces item to assume the bottom position in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 315
def assume_bottom_position
  set_list_position(bottom_position_in_list(self).to_i + 1)
end
assume_top_position() click to toggle source

Forces item to assume the top position in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 320
def assume_top_position
  set_list_position(acts_as_list_top)
end
bottom_item(except = nil) click to toggle source

Returns the bottom item

# File lib/acts_as_list/active_record/acts/list.rb, line 308
def bottom_item(except = nil)
  conditions = scope_condition
  conditions = "#{conditions} AND #{self.class.primary_key} != '#{except.id}'" if except
  acts_as_list_class.unscoped.in_list.where(conditions).order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
end
bottom_position_in_list(except = nil) click to toggle source

Returns the bottom position number in the list.

bottom_position_in_list    # => 2
# File lib/acts_as_list/active_record/acts/list.rb, line 302
def bottom_position_in_list(except = nil)
  item = bottom_item(except)
  item ? item.send(position_column) : acts_as_list_top - 1
end
check_scope() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 434
def check_scope
  if scope_changed?
    swap_changed_attributes
    send('decrement_positions_on_lower_items') if lower_item
    swap_changed_attributes
    send("add_to_list_#{add_new_at}")
  end
end
check_top_position() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 447
def check_top_position
  if send(position_column) && send(position_column) < acts_as_list_top
    self[position_column] = acts_as_list_top
  end
end
decrement_positions_on_higher_items(position) click to toggle source

This has the effect of moving all the higher items up one.

# File lib/acts_as_list/active_record/acts/list.rb, line 325
def decrement_positions_on_higher_items(position)
  acts_as_list_class.unscoped.where(
    "#{scope_condition} AND #{position_column} <= #{position}"
  ).update_all(
    "#{position_column} = (#{position_column} - 1)"
  )
end
decrement_positions_on_lower_items(position=nil) click to toggle source

This has the effect of moving all the lower items up one.

# File lib/acts_as_list/active_record/acts/list.rb, line 334
def decrement_positions_on_lower_items(position=nil)
  return unless in_list?
  position ||= send(position_column).to_i
  acts_as_list_class.unscoped.where(
    "#{scope_condition} AND #{position_column} > #{position}"
  ).update_all(
    "#{position_column} = (#{position_column} - 1)"
  )
end
increment_positions_on_all_items() click to toggle source

Increments position (position_column) of all items in the list.

# File lib/acts_as_list/active_record/acts/list.rb, line 364
def increment_positions_on_all_items
  acts_as_list_class.unscoped.where(
    "#{scope_condition}"
  ).update_all(
    "#{position_column} = (#{position_column} + 1)"
  )
end
increment_positions_on_higher_items() click to toggle source

This has the effect of moving all the higher items down one.

# File lib/acts_as_list/active_record/acts/list.rb, line 345
def increment_positions_on_higher_items
  return unless in_list?
  acts_as_list_class.unscoped.where(
    "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
  ).update_all(
    "#{position_column} = (#{position_column} + 1)"
  )
end
increment_positions_on_lower_items(position) click to toggle source

This has the effect of moving all the lower items down one.

# File lib/acts_as_list/active_record/acts/list.rb, line 355
def increment_positions_on_lower_items(position)
  acts_as_list_class.unscoped.where(
    "#{scope_condition} AND #{position_column} >= #{position}"
  ).update_all(
    "#{position_column} = (#{position_column} + 1)"
  )
end
insert_at_position(position) click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 399
def insert_at_position(position)
  return set_list_position(position) if new_record?
  if in_list?
    old_position = send(position_column).to_i
    return if position == old_position
    shuffle_positions_on_intermediate_items(old_position, position)
  else
    increment_positions_on_lower_items(position)
  end
  set_list_position(position)
end
reload_position() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 443
def reload_position
  self.reload
end
scope_condition() click to toggle source

Overwrite this method to define the scope of the list changes

# File lib/acts_as_list/active_record/acts/list.rb, line 298
def scope_condition() "1" end
shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil) click to toggle source

Reorders intermediate items to support moving an item from old_position to new_position.

# File lib/acts_as_list/active_record/acts/list.rb, line 373
def shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil)
  return if old_position == new_position
  avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != '#{avoid_id}'" : ''
  if old_position < new_position
    # Decrement position of intermediate items
    #
    # e.g., if moving an item from 2 to 5,
    # move [3, 4, 5] to [2, 3, 4]
    acts_as_list_class.unscoped.where(
      "#{scope_condition} AND #{position_column} > #{old_position} AND #{position_column} <= #{new_position}#{avoid_id_condition}"
    ).update_all(
      "#{position_column} = (#{position_column} - 1)"
    )
  else
    # Increment position of intermediate items
    #
    # e.g., if moving an item from 5 to 2,
    # move [2, 3, 4] to [3, 4, 5]
    acts_as_list_class.unscoped.where(
      "#{scope_condition} AND #{position_column} >= #{new_position} AND #{position_column} < #{old_position}#{avoid_id_condition}"
    ).update_all(
      "#{position_column} = (#{position_column} + 1)"
    )
  end
end
store_at_0() click to toggle source

used by #insert_at_position instead of #remove_from_list, as postgresql raises error if position_column has non-null constraint

# File lib/acts_as_list/active_record/acts/list.rb, line 412
def store_at_0
  if in_list?
    old_position = send(position_column).to_i
    set_list_position(0)
    decrement_positions_on_lower_items(old_position)
  end
end
swap_changed_attributes() click to toggle source

Temporarily swap changes attributes with current attributes

# File lib/acts_as_list/active_record/acts/list.rb, line 429
def swap_changed_attributes
  @changed_attributes.each { |k, _| @changed_attributes[k], self[k] =
    self[k], @changed_attributes[k] }
end
update_positions() click to toggle source
# File lib/acts_as_list/active_record/acts/list.rb, line 420
def update_positions
  old_position = send("#{position_column}_was").to_i
  new_position = send(position_column).to_i

  return unless acts_as_list_class.unscoped.where("#{scope_condition} AND #{position_column} = #{new_position}").count > 1
  shuffle_positions_on_intermediate_items old_position, new_position, id
end