acts_as_list 0.7.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +5 -13
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/dependabot.yml +6 -0
  4. data/.github/workflows/ci.yml +123 -0
  5. data/.gitignore +1 -0
  6. data/.travis.yml +50 -12
  7. data/Appraisals +39 -6
  8. data/CHANGELOG.md +565 -148
  9. data/Gemfile +19 -14
  10. data/README.md +206 -19
  11. data/Rakefile +4 -4
  12. data/acts_as_list.gemspec +16 -11
  13. data/gemfiles/rails_4_2.gemfile +18 -9
  14. data/gemfiles/rails_5_0.gemfile +31 -0
  15. data/gemfiles/rails_5_1.gemfile +31 -0
  16. data/gemfiles/rails_5_2.gemfile +31 -0
  17. data/gemfiles/rails_6_0.gemfile +31 -0
  18. data/gemfiles/rails_6_1.gemfile +31 -0
  19. data/gemfiles/rails_7_0.gemfile +31 -0
  20. data/init.rb +2 -0
  21. data/lib/acts_as_list/active_record/acts/active_record.rb +5 -0
  22. data/lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb +11 -0
  23. data/lib/acts_as_list/active_record/acts/aux_method_definer.rb +11 -0
  24. data/lib/acts_as_list/active_record/acts/callback_definer.rb +19 -0
  25. data/lib/acts_as_list/active_record/acts/list.rb +299 -306
  26. data/lib/acts_as_list/active_record/acts/no_update.rb +125 -0
  27. data/lib/acts_as_list/active_record/acts/position_column_method_definer.rb +101 -0
  28. data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +77 -0
  29. data/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb +28 -0
  30. data/lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb +15 -0
  31. data/lib/acts_as_list/version.rb +3 -1
  32. data/lib/acts_as_list.rb +11 -14
  33. data/test/database.yml +18 -0
  34. data/test/helper.rb +50 -2
  35. data/test/shared.rb +3 -0
  36. data/test/shared_array_scope_list.rb +21 -4
  37. data/test/shared_list.rb +86 -12
  38. data/test/shared_list_sub.rb +63 -2
  39. data/test/shared_no_addition.rb +50 -2
  40. data/test/shared_quoting.rb +23 -0
  41. data/test/shared_top_addition.rb +36 -13
  42. data/test/shared_zero_based.rb +13 -0
  43. data/test/test_default_scope_with_select.rb +33 -0
  44. data/test/test_joined_list.rb +61 -0
  45. data/test/test_list.rb +601 -84
  46. data/test/test_no_update_for_extra_classes.rb +131 -0
  47. data/test/test_no_update_for_scope_destruction.rb +69 -0
  48. data/test/test_no_update_for_subclasses.rb +56 -0
  49. data/test/test_scope_with_user_defined_foreign_key.rb +42 -0
  50. metadata +56 -22
  51. data/gemfiles/rails_3_2.gemfile +0 -24
  52. data/gemfiles/rails_4_1.gemfile +0 -24
data/test/shared_list.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shared
2
4
  module List
3
5
  def setup
@@ -8,6 +10,13 @@ module Shared
8
10
  end
9
11
  end
10
12
 
13
+ def test_current_position
14
+ first_item = ListMixin.where(parent_id: 5).first
15
+ assert_equal 1, first_item.current_position
16
+ first_item.remove_from_list
17
+ assert_nil first_item.current_position
18
+ end
19
+
11
20
  def test_reordering
12
21
  assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
13
22
 
@@ -60,6 +69,11 @@ module Shared
60
69
  assert !new.first?
61
70
  assert new.last?
62
71
 
72
+ new = ListMixin.acts_as_list_no_update { ListMixin.create(parent_id: 20) }
73
+ assert_equal_or_nil $default_position, new.pos
74
+ assert_equal $default_position.is_a?(Integer), new.first?
75
+ assert !new.last?
76
+
63
77
  new = ListMixin.create(parent_id: 20)
64
78
  assert_equal 3, new.pos
65
79
  assert !new.first?
@@ -81,6 +95,9 @@ module Shared
81
95
  new = ListMixin.create(parent_id: 20)
82
96
  assert_equal 3, new.pos
83
97
 
98
+ new_noup = ListMixin.acts_as_list_no_update { ListMixin.create(parent_id: 20) }
99
+ assert_equal_or_nil $default_position, new_noup.pos
100
+
84
101
  new4 = ListMixin.create(parent_id: 20)
85
102
  assert_equal 4, new4.pos
86
103
 
@@ -104,12 +121,32 @@ module Shared
104
121
 
105
122
  new4.reload
106
123
  assert_equal 5, new4.pos
124
+
125
+ new_noup.reload
126
+ assert_equal_or_nil $default_position, new_noup.pos
127
+
128
+ last1 = ListMixin.where('pos IS NOT NULL').order('pos').last
129
+ last2 = ListMixin.where('pos IS NOT NULL').order('pos').last
130
+ last1.insert_at(1)
131
+ last2.insert_at(1)
132
+ pos_list = ListMixin.where(parent_id: 20).order("pos ASC#{' NULLS FIRST' if ENV['DB'] == 'postgresql'}").map(&:pos)
133
+ assert_equal [$default_position, 1, 2, 3, 4, 5], pos_list
107
134
  end
108
135
 
109
- def test_delete_middle
110
- assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
136
+ def test_insert_at_after_dup
137
+ new1 = ListMixin.create(parent_id: 20)
138
+ new2 = ListMixin.create(parent_id: 20)
139
+ new3 = ListMixin.create(parent_id: 20)
140
+
141
+ duped = new1.dup
142
+ duped.save
143
+ [new1, new2, new3, duped].map(&:reload)
111
144
 
145
+ assert_equal [1, 2, 3, 4], [duped.pos, new1.pos, new2.pos, new3.pos]
146
+ end
112
147
 
148
+ def test_delete_middle
149
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
113
150
 
114
151
  ListMixin.where(id: 2).first.destroy
115
152
 
@@ -125,6 +162,12 @@ module Shared
125
162
 
126
163
  assert_equal 1, ListMixin.where(id: 3).first.pos
127
164
  assert_equal 2, ListMixin.where(id: 4).first.pos
165
+
166
+ ListMixin.acts_as_list_no_update { ListMixin.where(id: 3).first.destroy }
167
+
168
+ assert_equal [4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
169
+
170
+ assert_equal 2, ListMixin.where(id: 4).first.pos
128
171
  end
129
172
 
130
173
  def test_with_string_based_scope
@@ -142,7 +185,7 @@ module Shared
142
185
 
143
186
  def test_update_position_when_scope_changes
144
187
  assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
145
- parent = ListMixin.create(parent_id: 6)
188
+ ListMixin.create(parent_id: 6)
146
189
 
147
190
  ListMixin.where(id: 2).first.move_within_scope(6)
148
191
 
@@ -169,10 +212,8 @@ module Shared
169
212
 
170
213
  ListMixin.where(id: 2).first.remove_from_list
171
214
 
172
- assert_equal [2, 1, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
173
-
174
215
  assert_equal 1, ListMixin.where(id: 1).first.pos
175
- assert_equal nil, ListMixin.where(id: 2).first.pos
216
+ assert_nil ListMixin.where(id: 2).first.pos
176
217
  assert_equal 2, ListMixin.where(id: 3).first.pos
177
218
  assert_equal 3, ListMixin.where(id: 4).first.pos
178
219
  end
@@ -196,12 +237,9 @@ module Shared
196
237
  # We need to trigger all the before_destroy callbacks without actually
197
238
  # destroying the record so we can see the affect the callbacks have on
198
239
  # the record.
199
- # NOTE: Hotfix for rails3 ActiveRecord
200
240
  list = ListMixin.where(id: 2).first
201
241
  if list.respond_to?(:run_callbacks)
202
- # Refactored to work according to Rails3 ActiveRSupport Callbacks <http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html>
203
- list.run_callbacks(:destroy) if rails_3
204
- list.run_callbacks(:before_destroy) if !rails_3
242
+ list.run_callbacks(:destroy)
205
243
  else
206
244
  list.send(:callback, :before_destroy)
207
245
  end
@@ -237,14 +275,50 @@ module Shared
237
275
 
238
276
  assert_equal [5, 1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
239
277
 
278
+ new6 = ListMixin.new(parent_id: 5)
279
+ new6.pos = 3
280
+ new6.save!
281
+ assert_equal 3, new6.pos
282
+ assert !new6.first?
283
+ assert !new6.last?
284
+
285
+ assert_equal [5, 1, 6, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
286
+
240
287
  new = ListMixin.new(parent_id: 5)
241
288
  new.pos = 3
242
- new.save!
289
+ ListMixin.acts_as_list_no_update { new.save! }
243
290
  assert_equal 3, new.pos
291
+ assert_equal 3, new6.pos
244
292
  assert !new.first?
245
293
  assert !new.last?
246
294
 
247
- assert_equal [5, 1, 6, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
295
+ assert_equal [5, 1, 6, 7, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos, id').map(&:id)
296
+ end
297
+
298
+ def test_non_persisted_records_dont_get_lock_called
299
+ new = ListMixin.new(parent_id: 5)
300
+ new.destroy
301
+ end
302
+
303
+ def test_invalid_records_dont_get_inserted
304
+ new = ListMixinError.new(parent_id: 5, state: nil)
305
+ assert !new.valid?
306
+ new.insert_at(1)
307
+ assert !new.persisted?
308
+ end
309
+
310
+ def test_invalid_records_raise_error_with_insert_at!
311
+ new = ListMixinError.new(parent_id: 5, state: nil)
312
+ assert !new.valid?
313
+ assert_raises ActiveRecord::RecordInvalid do
314
+ new.insert_at!(1)
315
+ end
316
+ end
317
+
318
+ def test_find_or_create_doesnt_raise_deprecation_warning
319
+ assert_no_deprecation_warning_raised_by('ActiveRecord deprecation warning raised when using `find_or_create_by` when we didn\'t expect it') do
320
+ ListMixin.where(parent_id: 5).find_or_create_by(pos: 5)
321
+ end
248
322
  end
249
323
  end
250
324
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shared
2
4
  module ListSub
3
5
  def setup
@@ -43,6 +45,36 @@ module Shared
43
45
  assert_nil ListMixin.where(id: 4).first.lower_item
44
46
  end
45
47
 
48
+ def test_next_prev_not_regular_sequence
49
+ ListMixin.all.each do |item|
50
+ item.update pos: item.pos * 5
51
+ end
52
+
53
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
54
+ assert_equal [5, 10, 15, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
55
+
56
+ ListMixin.where(id: 2).first.move_lower
57
+ assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
58
+ assert_equal [5, 15, 10, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
59
+
60
+
61
+ ListMixin.where(id: 2).first.move_higher
62
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
63
+ assert_equal [5, 10, 15, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
64
+
65
+ ListMixin.where(id: 1).first.move_to_bottom
66
+ assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
67
+
68
+ ListMixin.where(id: 1).first.move_to_top
69
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
70
+
71
+ ListMixin.where(id: 2).first.move_to_bottom
72
+ assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
73
+
74
+ ListMixin.where(id: 4).first.move_to_top
75
+ assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
76
+ end
77
+
46
78
  def test_next_prev_groups
47
79
  li1 = ListMixin.where(id: 1).first
48
80
  li2 = ListMixin.where(id: 2).first
@@ -53,12 +85,29 @@ module Shared
53
85
  assert_equal [li2, li3], li1.lower_items(2)
54
86
  assert_equal [], li4.lower_items
55
87
 
56
- assert_equal [li1, li2], li3.higher_items
88
+ assert_equal [li2, li1], li3.higher_items
57
89
  assert_equal [li1], li2.higher_items
58
- assert_equal [li2, li3], li4.higher_items(2)
90
+ assert_equal [li3, li2], li4.higher_items(2)
59
91
  assert_equal [], li1.higher_items
60
92
  end
61
93
 
94
+ def test_next_prev_groups_with_same_position
95
+ li1 = ListMixin.where(id: 1).first
96
+ li2 = ListMixin.where(id: 2).first
97
+ li3 = ListMixin.where(id: 3).first
98
+ li4 = ListMixin.where(id: 4).first
99
+
100
+ li3.update_column(:pos, 2) # Make the same position as li2
101
+
102
+ assert_equal [1, 2, 2, 4], ListMixin.order(:pos).pluck(:pos)
103
+
104
+ assert_equal [li3, li4], li2.lower_items
105
+ assert_equal [li2, li4], li3.lower_items
106
+
107
+ assert_equal [li3, li1], li2.higher_items
108
+ assert_equal [li2, li1], li3.higher_items
109
+ end
110
+
62
111
  def test_injection
63
112
  item = ListMixin.new("parent_id"=>1)
64
113
  assert_equal({ parent_id: 1 }, item.scope_condition)
@@ -75,6 +124,9 @@ module Shared
75
124
  new = ListMixinSub1.create("parent_id" => 20)
76
125
  assert_equal 3, new.pos
77
126
 
127
+ new_noup = ListMixinSub1.acts_as_list_no_update { ListMixinSub1.create("parent_id" => 20) }
128
+ assert_equal_or_nil $default_position, new_noup.pos
129
+
78
130
  new4 = ListMixin.create("parent_id" => 20)
79
131
  assert_equal 4, new4.pos
80
132
 
@@ -98,6 +150,9 @@ module Shared
98
150
 
99
151
  new4.reload
100
152
  assert_equal 5, new4.pos
153
+
154
+ new_noup.reload
155
+ assert_equal_or_nil $default_position, new_noup.pos
101
156
  end
102
157
 
103
158
  def test_delete_middle
@@ -117,6 +172,12 @@ module Shared
117
172
 
118
173
  assert_equal 1, ListMixin.where(id: 3).first.pos
119
174
  assert_equal 2, ListMixin.where(id: 4).first.pos
175
+
176
+ ListMixin.acts_as_list_no_update { ListMixin.where(id: 3).first.destroy }
177
+
178
+ assert_equal [4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
179
+
180
+ assert_equal 2, ListMixin.where(id: 4).first.pos
120
181
  end
121
182
 
122
183
  def test_acts_as_list_class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shared
2
4
  module NoAddition
3
5
  def setup
@@ -6,11 +8,11 @@ module Shared
6
8
 
7
9
  def test_insert
8
10
  new = NoAdditionMixin.create(parent_id: 20)
9
- assert_equal nil, new.pos
11
+ assert_nil new.pos
10
12
  assert !new.in_list?
11
13
 
12
14
  new = NoAdditionMixin.create(parent_id: 20)
13
- assert_equal nil, new.pos
15
+ assert_nil new.pos
14
16
  end
15
17
 
16
18
  def test_update_does_not_add_to_list
@@ -21,5 +23,51 @@ module Shared
21
23
  assert !new.in_list?
22
24
  end
23
25
 
26
+ def test_update_scope_does_not_add_to_list
27
+ new = NoAdditionMixin.create
28
+
29
+ new.update_attribute(:parent_id, 20)
30
+ new.reload
31
+ assert !new.in_list?
32
+
33
+ new.update_attribute(:parent_id, 5)
34
+ new.reload
35
+ assert !new.in_list?
36
+ end
37
+
38
+ def test_collision_avoidance_with_explicit_position
39
+ first = NoAdditionMixin.create(parent_id: 20, pos: 1)
40
+ second = NoAdditionMixin.create(parent_id: 20, pos: 1)
41
+ third = NoAdditionMixin.create(parent_id: 30, pos: 1)
42
+
43
+ first.reload
44
+ second.reload
45
+ third.reload
46
+
47
+ assert_equal 2, first.pos
48
+ assert_equal 1, second.pos
49
+ assert_equal 1, third.pos
50
+
51
+ first.update(pos: 1)
52
+
53
+ first.reload
54
+ second.reload
55
+
56
+ assert_equal 1, first.pos
57
+ assert_equal 2, second.pos
58
+
59
+ first.update(parent_id: 30)
60
+
61
+ first.reload
62
+ second.reload
63
+ third.reload
64
+
65
+ assert_equal 1, first.pos
66
+ assert_equal 30, first.parent_id
67
+ assert_equal 1, second.pos
68
+ assert_equal 20, second.parent_id
69
+ assert_equal 2, third.pos
70
+ assert_equal 30, third.parent_id
71
+ end
24
72
  end
25
73
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shared
4
+ module Quoting
5
+
6
+ def setup
7
+ 3.times { |counter| QuotedList.create! order: counter }
8
+ end
9
+
10
+ def test_create
11
+ assert_equal QuotedList.in_list.size, 3
12
+ end
13
+
14
+ # This test execute raw queries involving table name
15
+ def test_moving
16
+ item = QuotedList.first
17
+ item.higher_items
18
+ item.lower_items
19
+ item.send :bottom_item # Part of private api
20
+ end
21
+
22
+ end
23
+ end
@@ -1,26 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shared
2
4
  module TopAddition
3
5
  def setup
4
6
  (1..4).each { |counter| TopAdditionMixin.create! pos: counter, parent_id: 5 }
5
7
  end
6
8
 
7
- def test_reordering
8
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
9
+ def test_setup_state
10
+ # If we explicitly define a position (as above) then that position is what gets applied
11
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
12
+ end
9
13
 
14
+ def test_reordering
10
15
  TopAdditionMixin.where(id: 2).first.move_lower
11
- assert_equal [4, 3, 1, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
16
+ assert_equal [1, 3, 2, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
12
17
 
13
18
  TopAdditionMixin.where(id: 2).first.move_higher
14
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
19
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
15
20
 
16
21
  TopAdditionMixin.where(id: 1).first.move_to_bottom
17
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
22
+ assert_equal [2, 3, 4, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
18
23
 
19
24
  TopAdditionMixin.where(id: 1).first.move_to_top
20
- assert_equal [1, 4, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
25
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
21
26
 
22
27
  TopAdditionMixin.where(id: 2).first.move_to_bottom
23
- assert_equal [1, 4, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
28
+ assert_equal [1, 3, 4, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
24
29
 
25
30
  TopAdditionMixin.where(id: 4).first.move_to_top
26
31
  assert_equal [4, 1, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
@@ -43,9 +48,14 @@ module Shared
43
48
  assert new.first?
44
49
  assert !new.last?
45
50
 
51
+ new = TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.create(parent_id: 20) }
52
+ assert_equal_or_nil $default_position, new.pos
53
+ assert_equal $default_position.is_a?(Integer), new.first?
54
+ assert !new.last?
55
+
46
56
  new = TopAdditionMixin.create(parent_id: 20)
47
57
  assert_equal 1, new.pos
48
- assert new.first?
58
+ assert_equal $default_position.nil?, new.first?
49
59
  assert !new.last?
50
60
 
51
61
  new = TopAdditionMixin.create(parent_id: 0)
@@ -64,6 +74,9 @@ module Shared
64
74
  new = TopAdditionMixin.create(parent_id: 20)
65
75
  assert_equal 1, new.pos
66
76
 
77
+ new = TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.create(parent_id: 20) }
78
+ assert_equal_or_nil $default_position, new.pos
79
+
67
80
  new4 = TopAdditionMixin.create(parent_id: 20)
68
81
  assert_equal 1, new4.pos
69
82
 
@@ -71,16 +84,26 @@ module Shared
71
84
  assert_equal 3, new4.pos
72
85
  end
73
86
 
74
- def test_delete_middle
75
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
87
+ def test_supplied_position
88
+ new = TopAdditionMixin.create(parent_id: 20, pos: 3)
89
+ assert_equal 3, new.pos
90
+ end
76
91
 
92
+ def test_delete_middle
77
93
  TopAdditionMixin.where(id: 2).first.destroy
78
94
 
79
- assert_equal [4, 3, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
95
+ assert_equal [1, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
80
96
 
81
- assert_equal 3, TopAdditionMixin.where(id: 1).first.pos
97
+ assert_equal 1, TopAdditionMixin.where(id: 1).first.pos
82
98
  assert_equal 2, TopAdditionMixin.where(id: 3).first.pos
83
- assert_equal 1, TopAdditionMixin.where(id: 4).first.pos
99
+ assert_equal 3, TopAdditionMixin.where(id: 4).first.pos
100
+
101
+ TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.where(id: 3).first.destroy }
102
+
103
+ assert_equal [1, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
104
+
105
+ assert_equal 1, TopAdditionMixin.where(id: 1).first.pos
106
+ assert_equal 3, TopAdditionMixin.where(id: 4).first.pos
84
107
  end
85
108
 
86
109
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shared
2
4
  module ZeroBased
3
5
  def setup
@@ -15,6 +17,11 @@ module Shared
15
17
  assert !new.first?
16
18
  assert new.last?
17
19
 
20
+ new = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
21
+ assert_equal_or_nil $default_position, new.pos
22
+ assert !new.first?
23
+ assert !new.last?
24
+
18
25
  new = ZeroBasedMixin.create(parent_id: 20)
19
26
  assert_equal 2, new.pos
20
27
  assert !new.first?
@@ -63,6 +70,9 @@ module Shared
63
70
  new = ZeroBasedMixin.create(parent_id: 20)
64
71
  assert_equal 2, new.pos
65
72
 
73
+ new_noup = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
74
+ assert_equal_or_nil $default_position, new_noup.pos
75
+
66
76
  new4 = ZeroBasedMixin.create(parent_id: 20)
67
77
  assert_equal 3, new4.pos
68
78
 
@@ -86,6 +96,9 @@ module Shared
86
96
 
87
97
  new4.reload
88
98
  assert_equal 4, new4.pos
99
+
100
+ new_noup.reload
101
+ assert_equal_or_nil $default_position, new_noup.pos
89
102
  end
90
103
  end
91
104
  end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class Animal < ActiveRecord::Base
4
+ acts_as_list
5
+ default_scope -> { select(:name) }
6
+ end
7
+
8
+ class DefaultScopeWithSelectTest < Minitest::Test
9
+ def setup
10
+ ActiveRecord::Base.connection.create_table :animals do |t|
11
+ t.column :position, :integer
12
+ t.column :name, :string
13
+ end
14
+
15
+ ActiveRecord::Base.connection.schema_cache.clear!
16
+ Animal.reset_column_information
17
+ super
18
+ end
19
+
20
+ def teardown
21
+ teardown_db
22
+ super
23
+ end
24
+
25
+ def test_default_scope_with_select
26
+ animal1 = Animal.create name: 'Fox'
27
+ animal2 = Animal.create name: 'Panda'
28
+ animal3 = Animal.create name: 'Wildebeast'
29
+ assert_equal 1, animal1.position
30
+ assert_equal 2, animal2.position
31
+ assert_equal 3, animal3.position
32
+ end
33
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'helper'
4
+
5
+ class Section < ActiveRecord::Base
6
+ has_many :items
7
+ acts_as_list
8
+
9
+ scope :visible, -> { where(visible: true) }
10
+ end
11
+
12
+ class Item < ActiveRecord::Base
13
+ belongs_to :section
14
+ acts_as_list scope: :section
15
+
16
+ scope :visible, -> { where(visible: true).joins(:section).merge(Section.visible) }
17
+ end
18
+
19
+ class JoinedTestCase < Minitest::Test
20
+ def setup
21
+ ActiveRecord::Base.connection.create_table :sections do |t|
22
+ t.column :position, :integer
23
+ t.column :visible, :boolean, default: true
24
+ end
25
+
26
+ ActiveRecord::Base.connection.create_table :items do |t|
27
+ t.column :position, :integer
28
+ t.column :section_id, :integer
29
+ t.column :visible, :boolean, default: true
30
+ end
31
+
32
+ ActiveRecord::Base.connection.schema_cache.clear!
33
+ [Section, Item].each(&:reset_column_information)
34
+ super
35
+ end
36
+
37
+ def teardown
38
+ teardown_db
39
+ super
40
+ end
41
+ end
42
+
43
+ # joining the relation returned by `#higher_items` or `#lower_items` to another table
44
+ # previously could result in ambiguous column names in the query
45
+ class TestHigherLowerItems < JoinedTestCase
46
+ def test_higher_items
47
+ section = Section.create
48
+ item1 = Item.create section: section
49
+ item2 = Item.create section: section
50
+ item3 = Item.create section: section
51
+ assert_equal item3.higher_items.visible, [item2, item1]
52
+ end
53
+
54
+ def test_lower_items
55
+ section = Section.create
56
+ item1 = Item.create section: section
57
+ item2 = Item.create section: section
58
+ item3 = Item.create section: section
59
+ assert_equal item1.lower_items.visible, [item2, item3]
60
+ end
61
+ end