forked from brendon/positioning
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpositioning.rb
More file actions
81 lines (63 loc) · 2.62 KB
/
positioning.rb
File metadata and controls
81 lines (63 loc) · 2.62 KB
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
require_relative "positioning/version"
require_relative "positioning/mechanisms"
require_relative "positioning/healer"
require "active_support/concern"
require "active_support/lazy_load_hooks"
module Positioning
class Error < StandardError; end
RelativePosition = Struct.new(:before, :after, keyword_init: true)
module Behaviour
extend ActiveSupport::Concern
class_methods do
def positioning_columns
@positioning_columns ||= {}
end
def positioned(on: [], column: :position)
unless base_class?
raise Error.new "can't be called on an abstract class or STI subclass."
end
column = column.to_sym
if positioning_columns.key? column
raise Error.new "The column `#{column}` has already been used by the scope `#{positioning_columns[column]}`."
else
positioning_columns[column] = {scope_columns: [], scope_associations: []}
Array.wrap(on).each do |scope_component|
scope_component = scope_component.to_s
reflection = reflections[scope_component]
if reflection&.belongs_to?
positioning_columns[column][:scope_columns] << reflection.foreign_key
positioning_columns[column][:scope_columns] << reflection.foreign_type if reflection.polymorphic?
positioning_columns[column][:scope_associations] << reflection.name
else
positioning_columns[column][:scope_columns] << scope_component
end
end
define_method(:"prior_#{column}") { Mechanisms.new(self, column).prior }
define_method(:"subsequent_#{column}") { Mechanisms.new(self, column).subsequent }
redefine_method(:"#{column}=") do |position|
send :"#{column}_will_change!"
super(position)
end
before_create { Mechanisms.new(self, column).create_position }
before_update { Mechanisms.new(self, column).update_position }
before_destroy { Mechanisms.new(self, column).destroy_position }
define_singleton_method(:"heal_#{column}_column!") do |order = column|
Healer.new(self, column).heal(order)
end
define_singleton_method(:"update_#{column}_in_order_of!") do |ids|
Healer.new(self, column).reposition(ids)
end
end
end
end
def initialize_dup(other)
super
self.class.positioning_columns.keys.each do |positioning_column|
send :"#{positioning_column}=", nil
end
end
end
end
ActiveSupport.on_load :active_record do
ActiveRecord::Base.send :include, Positioning::Behaviour
end