acts_as_list 0.7.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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