acts_as_list 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d62dacdeb7972152a2ee04cee3cccb8ef26898d7
4
- data.tar.gz: fe6b02bfa1c5ed33407d1852c7b988a1848c7cd4
3
+ metadata.gz: cf7464bb2c953b31ccf95b2e3017ce77cf9e40bc
4
+ data.tar.gz: f65a617c773c1c5ebad2b85827fc675da6c23d2c
5
5
  SHA512:
6
- metadata.gz: 6b376b14646463802f4aee7080663eefdb3d7b1a43088df7126f57c84ecfb0a8730470efe4b57758f2b2079d6bd52b19f2a80293b211095318425d5892194897
7
- data.tar.gz: fa104b99749d08767074e96f5fea1e97590ee841673660c39d03bb3d2cd50a3d2db2de4d1d195d5503d1bfadec7cbe84e046714f0ab98d0d509bc4c4797949e2
6
+ metadata.gz: 664518e270eafe5380772fe9dab0d661ab6184b526648ba1322f28d4c04040e9d412f00b011abe072eb289d73dc422be0aa411b1e759d2933c5ea05d08ef8773
7
+ data.tar.gz: ffd987ff9646c697fe2972ff2516bcc66286d528c71af311e8fe27524568d5eaad6ee774cd351345a2c8aaad8326fd9c42bd83dd9acf77d3f34dfb2a98d99d2d
@@ -1,5 +1,20 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.7.7](https://github.com/swanandp/acts_as_list/tree/v0.7.7) (2016-08-18)
4
+ [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.6...v0.7.7)
5
+
6
+ **Closed issues:**
7
+
8
+ - Issue after upgrading to 0.7.5: No connection pool with id primary found. [\#214](https://github.com/swanandp/acts_as_list/issues/214)
9
+ - Changing scope is inconsistent based on add\_new\_at [\#138](https://github.com/swanandp/acts_as_list/issues/138)
10
+ - Duplicate positions and lost items [\#76](https://github.com/swanandp/acts_as_list/issues/76)
11
+
12
+ **Merged pull requests:**
13
+
14
+ - Add quoted table names to some columns [\#221](https://github.com/swanandp/acts_as_list/pull/221) ([jpalumickas](https://github.com/jpalumickas))
15
+ - Appraisals cleanup [\#217](https://github.com/swanandp/acts_as_list/pull/217) ([brendon](https://github.com/brendon))
16
+ - Fix insert\_at\_position in race condition [\#195](https://github.com/swanandp/acts_as_list/pull/195) ([danielross](https://github.com/danielross))
17
+
3
18
  ## [v0.7.6](https://github.com/swanandp/acts_as_list/tree/v0.7.6) (2016-07-15)
4
19
  [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.5...v0.7.6)
5
20
 
data/README.md CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  This `acts_as` extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a `position` column defined as an integer on the mapped database table.
6
6
 
7
+ ## 0.8.0 Upgrade Notes
8
+
9
+ There are a couple of changes of behaviour from `0.8.0` onwards:
10
+
11
+ - If you specify `add_new_at: :top`, new items will be added to the top of the list like always. But now, if you specify a position at insert time: `.create(position: 3)`, the position will be respected. In this example, the item will end up at position `3` and will move other items further down the list. Before `0.8.0` the position would be ignored and the item would still be added to the top of the list. [#220](https://github.com/swanandp/acts_as_list/pull/220)
12
+ - `acts_as_list` now copes with disparate position integers (i.e. gaps between the numbers). There has been a change in behaviour for the `higher_items` method. It now returns items with the first item in the collection being the closest item to the reference item, and the last item in the collection being the furthest from the reference item (a.k.a. the first item in the list). [#223](https://github.com/swanandp/acts_as_list/pull/223)
13
+
7
14
  ## Installation
8
15
 
9
16
  In your Gemfile:
@@ -71,8 +78,6 @@ In `acts_as_list`, "higher" means further up the list (a lower `position`), and
71
78
  - `list_item.lower_items` will return all the items below `list_item` in the list (ordered by the position, ascending)
72
79
 
73
80
  ## Notes
74
- If the `position` column has a default value, then there is a slight change in behavior, i.e if you have 4 items in the list, and you insert 1, with a default position 0, it would be pushed to the bottom of the list. Please look at the tests for this and some recent pull requests for discussions related to this.
75
-
76
81
  All `position` queries (select, update, etc.) inside gem methods are executed without the default scope (i.e. `Model.unscoped`), this will prevent nasty issues when the default scope is different from `acts_as_list` scope.
77
82
 
78
83
  The `position` column is set after validations are called, so you should not put a `presence` validation on the `position` column.
@@ -88,11 +93,11 @@ end
88
93
 
89
94
  ## More Options
90
95
  - `column`
91
- default: 'position'. Use this option if the column name in your database is different from position.
96
+ default: `position`. Use this option if the column name in your database is different from position.
92
97
  - `top_of_list`
93
- default: '1'. Use this option to define the top of the list. Use 0 to make the collection act more like an array in its indexing.
98
+ default: `1`. Use this option to define the top of the list. Use 0 to make the collection act more like an array in its indexing.
94
99
  - `add_new_at`
95
- default: ':bottom'. Use this option to specify whether objects get added to the :top or :bottom of the list. `nil` will result in new items not being added to the list on create, i.e, position will be kept nil after create.
100
+ default: `:bottom`. Use this option to specify whether objects get added to the `:top` or `:bottom` of the list. `nil` will result in new items not being added to the list on create, i.e, position will be kept nil after create.
96
101
 
97
102
  ## Versions
98
103
  As of version `0.7.5` Rails 5 is supported.
@@ -16,10 +16,4 @@ group :test do
16
16
  gem "after_commit_exception_notification"
17
17
  end
18
18
 
19
- platforms :rbx do
20
- gem "rubysl", "~> 2.0"
21
- gem "rubinius-developer_tools"
22
- gem "rubysl-test-unit"
23
- end
24
-
25
19
  gemspec :path => "../"
@@ -174,8 +174,12 @@ module ActiveRecord
174
174
  return unless lower_item
175
175
 
176
176
  acts_as_list_class.transaction do
177
- lower_item.decrement_position
178
- increment_position
177
+ if lower_item.send(position_column) != self.send(position_column)
178
+ swap_positions(lower_item, self)
179
+ else
180
+ lower_item.decrement_position
181
+ increment_position
182
+ end
179
183
  end
180
184
  end
181
185
 
@@ -184,8 +188,12 @@ module ActiveRecord
184
188
  return unless higher_item
185
189
 
186
190
  acts_as_list_class.transaction do
187
- higher_item.increment_position
188
- decrement_position
191
+ if higher_item.send(position_column) != self.send(position_column)
192
+ swap_positions(higher_item, self)
193
+ else
194
+ higher_item.increment_position
195
+ decrement_position
196
+ end
189
197
  end
190
198
  end
191
199
 
@@ -236,16 +244,14 @@ module ActiveRecord
236
244
  set_list_position(self.send(position_column).to_i - 1)
237
245
  end
238
246
 
239
- # Return +true+ if this object is the first in the list.
240
247
  def first?
241
248
  return false unless in_list?
242
- self.send(position_column) == acts_as_list_top
249
+ !higher_item
243
250
  end
244
251
 
245
- # Return +true+ if this object is the last in the list.
246
252
  def last?
247
253
  return false unless in_list?
248
- self.send(position_column) == bottom_position_in_list
254
+ !lower_item
249
255
  end
250
256
 
251
257
  # Return the next higher item in the list.
@@ -261,9 +267,8 @@ module ActiveRecord
261
267
  position_value = send(position_column)
262
268
  acts_as_list_list.
263
269
  where("#{quoted_position_column_with_table_name} < ?", position_value).
264
- where("#{quoted_position_column_with_table_name} >= ?", position_value - limit).
265
- limit(limit).
266
- order("#{quoted_position_column_with_table_name} ASC")
270
+ order("#{quoted_position_column_with_table_name} DESC").
271
+ limit(limit)
267
272
  end
268
273
 
269
274
  # Return the next lower item in the list.
@@ -279,9 +284,8 @@ module ActiveRecord
279
284
  position_value = send(position_column)
280
285
  acts_as_list_list.
281
286
  where("#{quoted_position_column_with_table_name} > ?", position_value).
282
- where("#{quoted_position_column_with_table_name} <= ?", position_value + limit).
283
- limit(limit).
284
- order("#{quoted_position_column_with_table_name} ASC")
287
+ order("#{quoted_position_column_with_table_name} ASC").
288
+ limit(limit)
285
289
  end
286
290
 
287
291
  # Test if this record is in a list
@@ -308,23 +312,36 @@ module ActiveRecord
308
312
  end
309
313
 
310
314
  private
315
+
316
+ def swap_positions(item1, item2)
317
+ item1.set_list_position(item2.send(position_column))
318
+ item2.set_list_position(item1.send("#{position_column}_was"))
319
+ end
320
+
311
321
  def acts_as_list_list
312
322
  acts_as_list_class.unscoped do
313
323
  acts_as_list_class.where(scope_condition)
314
324
  end
315
325
  end
316
326
 
327
+ # Poorly named methods. They will insert the item at the desired position if the position
328
+ # has been set manually using position=, not necessarily the top or bottom of the list:
329
+
317
330
  def add_to_list_top
318
- increment_positions_on_all_items
319
- self[position_column] = acts_as_list_top
331
+ if not_in_list? || internal_scope_changed? && !position_changed || default_position?
332
+ increment_positions_on_all_items
333
+ self[position_column] = acts_as_list_top
334
+ else
335
+ increment_positions_on_lower_items(self[position_column], id)
336
+ end
337
+
320
338
  # Make sure we know that we've processed this scope change already
321
339
  @scope_changed = false
322
- #dont halt the callback chain
340
+
341
+ # Don't halt the callback chain
323
342
  true
324
343
  end
325
344
 
326
- # A poorly named method. It will insert the item at the desired position if the position
327
- # has been set manually using position=, not necessarily the bottom of the list
328
345
  def add_to_list_bottom
329
346
  if not_in_list? || internal_scope_changed? && !position_changed || default_position?
330
347
  self[position_column] = bottom_position_in_list.to_i + 1
@@ -335,7 +352,7 @@ module ActiveRecord
335
352
  # Make sure we know that we've processed this scope change already
336
353
  @scope_changed = false
337
354
 
338
- #dont halt the callback chain
355
+ # Don't halt the callback chain
339
356
  true
340
357
  end
341
358
 
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module List
4
- VERSION = '0.7.7'
4
+ VERSION = '0.8.0'
5
5
  end
6
6
  end
7
7
  end
@@ -43,6 +43,32 @@ module Shared
43
43
  assert_nil ListMixin.where(id: 4).first.lower_item
44
44
  end
45
45
 
46
+ def test_next_prev_not_regular_sequence
47
+ ListMixin.all.each do |item|
48
+ item.update_attributes(pos: item.pos * 5)
49
+ end
50
+
51
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
52
+
53
+ ListMixin.where(id: 2).first.move_lower
54
+ assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
55
+
56
+ ListMixin.where(id: 2).first.move_higher
57
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
58
+
59
+ ListMixin.where(id: 1).first.move_to_bottom
60
+ assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
61
+
62
+ ListMixin.where(id: 1).first.move_to_top
63
+ assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
64
+
65
+ ListMixin.where(id: 2).first.move_to_bottom
66
+ assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
67
+
68
+ ListMixin.where(id: 4).first.move_to_top
69
+ assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
70
+ end
71
+
46
72
  def test_next_prev_groups
47
73
  li1 = ListMixin.where(id: 1).first
48
74
  li2 = ListMixin.where(id: 2).first
@@ -53,9 +79,9 @@ module Shared
53
79
  assert_equal [li2, li3], li1.lower_items(2)
54
80
  assert_equal [], li4.lower_items
55
81
 
56
- assert_equal [li1, li2], li3.higher_items
82
+ assert_equal [li2, li1], li3.higher_items
57
83
  assert_equal [li1], li2.higher_items
58
- assert_equal [li2, li3], li4.higher_items(2)
84
+ assert_equal [li3, li2], li4.higher_items(2)
59
85
  assert_equal [], li1.higher_items
60
86
  end
61
87
 
@@ -4,23 +4,26 @@ module Shared
4
4
  (1..4).each { |counter| TopAdditionMixin.create! pos: counter, parent_id: 5 }
5
5
  end
6
6
 
7
- def test_reordering
8
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
7
+ def test_setup_state
8
+ # If we explicitly define a position (as above) then that position is what gets applied
9
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
10
+ end
9
11
 
12
+ def test_reordering
10
13
  TopAdditionMixin.where(id: 2).first.move_lower
11
- assert_equal [4, 3, 1, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
14
+ assert_equal [1, 3, 2, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
12
15
 
13
16
  TopAdditionMixin.where(id: 2).first.move_higher
14
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
17
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
15
18
 
16
19
  TopAdditionMixin.where(id: 1).first.move_to_bottom
17
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
20
+ assert_equal [2, 3, 4, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
18
21
 
19
22
  TopAdditionMixin.where(id: 1).first.move_to_top
20
- assert_equal [1, 4, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
23
+ assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
21
24
 
22
25
  TopAdditionMixin.where(id: 2).first.move_to_bottom
23
- assert_equal [1, 4, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
26
+ assert_equal [1, 3, 4, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
24
27
 
25
28
  TopAdditionMixin.where(id: 4).first.move_to_top
26
29
  assert_equal [4, 1, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
@@ -71,16 +74,19 @@ module Shared
71
74
  assert_equal 3, new4.pos
72
75
  end
73
76
 
74
- def test_delete_middle
75
- assert_equal [4, 3, 2, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
77
+ def test_supplied_position
78
+ new = TopAdditionMixin.create(parent_id: 20, pos: 3)
79
+ assert_equal 3, new.pos
80
+ end
76
81
 
82
+ def test_delete_middle
77
83
  TopAdditionMixin.where(id: 2).first.destroy
78
84
 
79
- assert_equal [4, 3, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
85
+ assert_equal [1, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
80
86
 
81
- assert_equal 3, TopAdditionMixin.where(id: 1).first.pos
87
+ assert_equal 1, TopAdditionMixin.where(id: 1).first.pos
82
88
  assert_equal 2, TopAdditionMixin.where(id: 3).first.pos
83
- assert_equal 1, TopAdditionMixin.where(id: 4).first.pos
89
+ assert_equal 3, TopAdditionMixin.where(id: 4).first.pos
84
90
  end
85
91
 
86
92
  end
@@ -51,7 +51,7 @@ class TestHigherLowerItems < JoinedTestCase
51
51
  item1 = Item.create section: section
52
52
  item2 = Item.create section: section
53
53
  item3 = Item.create section: section
54
- assert_equal item3.higher_items.visible, [item1, item2]
54
+ assert_equal item3.higher_items.visible, [item2, item1]
55
55
  end
56
56
 
57
57
  def test_lower_items
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.7
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-08-18 00:00:00.000000000 Z
13
+ date: 2016-08-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord