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
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
# 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
# File lib/acts_as_list/active_record/acts/list.rb, line 268 def default_position? default_position == send(position_column) end
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
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
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
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
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 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
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
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
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
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
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 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 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 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
# File lib/acts_as_list/active_record/acts/list.rb, line 260 def not_in_list? send(position_column).nil? end
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
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
# 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
# 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
# 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
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
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
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
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
# 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
# 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
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
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
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
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
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
# 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
# File lib/acts_as_list/active_record/acts/list.rb, line 443 def reload_position self.reload end
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
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
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
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
# 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