Alternative approach to drag and drop sorting with acts_as_list

Curated ago by @jeremysmithco

Description

Here’s an somewhat unconventional approach to drag and drop sorting using acts_as_list I came up with this week. In the old days, I would have implemented something similar to this RailsCasts episode. But I think I might like this better.

I made a YouTube video explaining my thinking.

As Chris Oliver notes, it’s probably best to use Signed Global IDs to avoid users tampering with model names and IDs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module ListInsertable
  extend ActiveSupport::Concern

  included do
    def insert_after(precursor)
      return if self == precursor
      return move_to_top if precursor.blank?

      raise ArgumentError, "Scope conditions do not match" unless scope_condition == precursor.scope_condition
      raise ArgumentError, "Precursor is not in list" unless precursor.in_list?

      insertion_position = insertion_position(precursor)

      return if position == insertion_position

      insert_at(insertion_position)
    end
  end

  private

  def insertion_position(precursor)
    return precursor.position + 1 if position.blank?
    return precursor.position + 1 if position > precursor.position

    precursor.position
  end
end

I’m not sure this is final form, but I think it’s close.