92 lines
3.6 KiB
Ruby
92 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Helpers
|
|
module ReorderPosition
|
|
|
|
# Function which insert object inside existing list
|
|
def insert_position(model)
|
|
# Get current currency amount
|
|
count = model.class.count
|
|
|
|
# If position value greater than currency amount
|
|
# System should add this object in the end of the list
|
|
# For example:
|
|
# List size eq to 15 and user want to set position to 24, system will set it on 16 position
|
|
if model.position > count
|
|
# Use update_column in favor of update to skip callback methods
|
|
model.update_column(:position, count)
|
|
elsif model.position == count
|
|
# System shouldn't reorder objects if new object has last position in the list
|
|
return
|
|
else
|
|
# As soon as create doesnt have old position value
|
|
# System will move the list up to the highest position(count)
|
|
# So techically old position == highest_position = count
|
|
highest_position = count
|
|
# Current model position
|
|
new_position = model.position
|
|
|
|
shuffle_positions_on_intermediate_items(model, highest_position, new_position)
|
|
end
|
|
end
|
|
|
|
# Function which update object inside existing list
|
|
def update_position(model)
|
|
# Get current currency amount
|
|
count = model.class.count
|
|
|
|
# Previous model position
|
|
old_position = model.position_was
|
|
# If new position value greater than currency amount
|
|
# System should add this object in the end of the list
|
|
new_position = model.position > count ? count : model.position
|
|
|
|
shuffle_positions_on_intermediate_items(model, old_position, new_position)
|
|
end
|
|
|
|
private
|
|
|
|
def shuffle_positions_on_intermediate_items(model, old_position, new_position)
|
|
# https://apidock.com/rails/String/tableize
|
|
# Currency => currencies Market => markets
|
|
table_name = model.class.name.tableize
|
|
|
|
# Define SQL query for reordering positions
|
|
sql = if old_position > new_position
|
|
increment_positions_on_lower_items(model.id, table_name, old_position, new_position)
|
|
else
|
|
decrement_positions_on_higher_items(model.id, table_name, old_position, new_position)
|
|
end
|
|
|
|
ActiveRecord::Base.transaction do
|
|
# Use update_column in favor of update to skip callback methods
|
|
# Set position as 0 before reordering
|
|
# Top list position starts from 1, so 0 is safe place for those updating
|
|
model.update_column(:position, 0)
|
|
# Reorder ojects in the list
|
|
ActiveRecord::Base.connection.execute(sql)
|
|
# Update object with desired position
|
|
model.update_column(:position, new_position)
|
|
end
|
|
end
|
|
|
|
# Updates objects positions between old position and new position
|
|
# If old position > new position
|
|
def increment_positions_on_lower_items(model_id, table_name, old_position, new_position)
|
|
"UPDATE #{table_name} SET position = (#{table_name}.position + 1) "\
|
|
"WHERE (#{table_name}.id != '#{model_id}') "\
|
|
"AND (#{table_name}.position >= #{new_position}) "\
|
|
"AND (#{table_name}.position < #{old_position})"
|
|
end
|
|
|
|
# Updates objects positions between old position and new position
|
|
# If old position < new position
|
|
def decrement_positions_on_higher_items(model_id, table_name, old_position, new_position)
|
|
"UPDATE #{table_name} SET position = (#{table_name}.position - 1) "\
|
|
"WHERE (#{table_name}.id != '#{model_id}') "\
|
|
"AND (#{table_name}.position > #{old_position}) "\
|
|
"AND (#{table_name}.position <= #{new_position})"
|
|
end
|
|
end
|
|
end
|