Module: Plutonium::Positioning::Model

Extended by:
ActiveSupport::Concern
Defined in:
lib/plutonium/positioning/model.rb

Overview

Standalone decimal/fractional ordering. Kanban-independent.

Including this concern and calling positioned_on gives a model:

  • automatic position assignment on create (appends to the end of its scope group)
  • reposition!(prev_record:, next_record:) for drag-and-drop reordering
  • backfill_positions! class method to number existing rows

This lives one level below Plutonium::Positioning on purpose. A concern is mixed into user models, and every constant nested in the included module joins that model's constant lookup — so a concern named Positioning would make a bare Config inside the model resolve to Plutonium::Positioning::Config, silently shadowing the app's own ::Config. Keeping the namespace and the mixin separate stops the leak.

Instance Method Summary collapse

Instance Method Details

#reposition!(prev_record:, next_record:) ⇒ Plutonium::Positioning::Result

Move this record so it sits between prev_record and next_record within its scope group. Pass nil for either neighbor to move to an end.

If the gap between the two neighbors is exhausted (too small to split) the scope group is rebalanced first so that fresh integer positions are available, then the record is positioned between the reloaded neighbors.

Parameters:

  • prev_record (ActiveRecord::Base, nil)
  • next_record (ActiveRecord::Base, nil)

Returns:

  • (Plutonium::Positioning::Result)

    whose rebalanced? tells the caller whether rows OTHER than this one moved — a drag-and-drop client that optimistically reordered its own view needs to re-sync when so.



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/plutonium/positioning/model.rb', line 83

def reposition!(prev_record:, next_record:)
  col = self.class.positioning_column
  prev_val = prev_record&.public_send(col)
  next_val = next_record&.public_send(col)
  rebalanced = Plutonium::Positioning.gap_exhausted?(prev_val, next_val)
  if rebalanced
    rebalance_scope_group!
    prev_val = prev_record&.reload&.public_send(col)
    next_val = next_record&.reload&.public_send(col)
  end
  update!(col => Plutonium::Positioning.position_between(prev_val, next_val))
  Plutonium::Positioning::Result.new(rebalanced:)
end