acts_as_list 1.0.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +123 -0
- data/Appraisals +5 -1
- data/CHANGELOG.md +6 -0
- data/README.md +8 -5
- data/gemfiles/rails_6_1.gemfile +1 -1
- data/gemfiles/rails_7_0.gemfile +31 -0
- data/lib/acts_as_list/active_record/acts/callback_definer.rb +2 -4
- data/lib/acts_as_list/active_record/acts/list.rb +19 -28
- data/lib/acts_as_list/version.rb +1 -1
- data/test/database.yml +3 -1
- data/test/shared_no_addition.rb +35 -0
- data/test/test_list.rb +36 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ece77b4a7a9c6c50d1d7a188c91c6dedd4c1dba4c8ece714c2922b339c3b5490
|
4
|
+
data.tar.gz: e7d925c76332e504d6a3db3706c4362b962d5bef2f9c882023bef99a0763e2d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ca617673d046ef18baab0a51d4e481ac10e7b044c569a9efb201c894be702aec66eb72cbc5364bb85b6374c144990fcc3c367b01cc62e0f431d87b6e41e0f4f
|
7
|
+
data.tar.gz: c1ce411f1aa503b28a837b714db52a4bcb42ae78542183f6641aa0d0f483c9c98b3521a4557554e9de539b12effeee6f901632636d61408e423c55d67287f47b
|
@@ -0,0 +1,123 @@
|
|
1
|
+
---
|
2
|
+
name: CI
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
tests:
|
7
|
+
name: Ruby ${{ matrix.ruby }}, ${{ matrix.gemfile }}, DB ${{ matrix.db }}
|
8
|
+
runs-on: ${{ matrix.os }}
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
matrix:
|
12
|
+
ruby:
|
13
|
+
- 2.4
|
14
|
+
- 2.5
|
15
|
+
- 2.6
|
16
|
+
- 2.7
|
17
|
+
- '3.0'
|
18
|
+
- 3.1
|
19
|
+
- 3.2
|
20
|
+
gemfile:
|
21
|
+
- gemfiles/rails_4_2.gemfile
|
22
|
+
- gemfiles/rails_5_0.gemfile
|
23
|
+
- gemfiles/rails_5_1.gemfile
|
24
|
+
- gemfiles/rails_5_2.gemfile
|
25
|
+
- gemfiles/rails_6_0.gemfile
|
26
|
+
- gemfiles/rails_6_1.gemfile
|
27
|
+
- gemfiles/rails_7_0.gemfile
|
28
|
+
db:
|
29
|
+
- sqlite
|
30
|
+
- mysql
|
31
|
+
- postgresql
|
32
|
+
exclude:
|
33
|
+
- ruby: 2.4
|
34
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
35
|
+
- ruby: 2.4
|
36
|
+
gemfile: gemfiles/rails_6_1.gemfile
|
37
|
+
- ruby: 2.4
|
38
|
+
gemfile: gemfiles/rails_7_0.gemfile
|
39
|
+
- ruby: 2.5
|
40
|
+
gemfile: gemfiles/rails_7_0.gemfile
|
41
|
+
- ruby: 2.6
|
42
|
+
gemfile: gemfiles/rails_7_0.gemfile
|
43
|
+
- ruby: 2.7
|
44
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
45
|
+
- ruby: 2.7
|
46
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
47
|
+
db: sqlite
|
48
|
+
- ruby: '3.0'
|
49
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
50
|
+
- ruby: '3.0'
|
51
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
52
|
+
- ruby: '3.0'
|
53
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
54
|
+
- ruby: '3.0'
|
55
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
56
|
+
- ruby: 3.1
|
57
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
58
|
+
- ruby: 3.1
|
59
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
60
|
+
- ruby: 3.1
|
61
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
62
|
+
- ruby: 3.1
|
63
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
64
|
+
- ruby: 3.1
|
65
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
66
|
+
- ruby: 3.2
|
67
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
68
|
+
- ruby: 3.2
|
69
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
70
|
+
- ruby: 3.2
|
71
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
72
|
+
- ruby: 3.2
|
73
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
74
|
+
- ruby: 3.2
|
75
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
76
|
+
- ruby: 3.2
|
77
|
+
gemfile: gemfiles/rails_6_1.gemfile
|
78
|
+
os:
|
79
|
+
- ubuntu-latest
|
80
|
+
services:
|
81
|
+
mysql:
|
82
|
+
image: mysql:5.7
|
83
|
+
env:
|
84
|
+
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
85
|
+
ports:
|
86
|
+
- 3306:3306
|
87
|
+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
88
|
+
|
89
|
+
postgres:
|
90
|
+
# Docker Hub image
|
91
|
+
image: postgres
|
92
|
+
# Provide the password for postgres
|
93
|
+
env:
|
94
|
+
POSTGRES_USER: postgres
|
95
|
+
POSTGRES_HOST_AUTH_METHOD: trust
|
96
|
+
ports:
|
97
|
+
- 5432:5432
|
98
|
+
# Set health checks to wait until postgres has started
|
99
|
+
options: >-
|
100
|
+
--health-cmd pg_isready
|
101
|
+
--health-interval 10s
|
102
|
+
--health-timeout 5s
|
103
|
+
--health-retries 5
|
104
|
+
env:
|
105
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
106
|
+
DB: ${{ matrix.db }}
|
107
|
+
steps:
|
108
|
+
- uses: actions/checkout@v3
|
109
|
+
- name: Set up Ruby
|
110
|
+
uses: ruby/setup-ruby@v1
|
111
|
+
with:
|
112
|
+
ruby-version: ${{ matrix.ruby }}
|
113
|
+
bundler-cache: true
|
114
|
+
- name: "Create MySQL database"
|
115
|
+
if: ${{ env.DB == 'mysql' }}
|
116
|
+
run: |
|
117
|
+
mysql -h 127.0.0.1 -u root -e 'create database acts_as_list;'
|
118
|
+
- name: "Create PostgreSQL database"
|
119
|
+
if: ${{ env.DB == 'postgresql' }}
|
120
|
+
run: |
|
121
|
+
psql -c 'create database acts_as_list;' -h localhost -U postgres
|
122
|
+
- name: Run tests
|
123
|
+
run: bundle exec rake
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## Unreleased
|
8
8
|
|
9
|
+
## v1.1.0 - 2023-02-01
|
10
|
+
|
11
|
+
### Fixed (Possibly Breaking)
|
12
|
+
- Use `after_save` instead of `after_commit` for `clear_scope_changed` callback [\#407](https://github.com/brendon/acts_as_list/pull/407) ([@Flixt](https://github.com/Flixt))
|
13
|
+
- Rename `add_to_list_top` and `add_to_list_bottom` private methods to `avoid_collision` that handles both cases as well as the case where `:add_new_at` is `nil`. Setting an explicit position when `:add_new_at` is `nil` will now shuffle other items out of the way if necessary. *This may break existing workarounds you have in place to deal with this bug*. [\#411](https://github.com/brendon/acts_as_list/pull/411). ([brendon])
|
14
|
+
|
9
15
|
## v1.0.4 - 2021-04-20
|
10
16
|
|
11
17
|
### Fixed
|
data/README.md
CHANGED
@@ -133,26 +133,29 @@ The `position` column is set after validations are called, so you should not put
|
|
133
133
|
If you need a scope by a non-association field you should pass an array, containing field name, to a scope:
|
134
134
|
```ruby
|
135
135
|
class TodoItem < ActiveRecord::Base
|
136
|
-
# `
|
137
|
-
acts_as_list scope: [:
|
136
|
+
# `task_category` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
|
137
|
+
acts_as_list scope: [:task_category]
|
138
138
|
end
|
139
139
|
```
|
140
140
|
|
141
141
|
You can also add multiple scopes in this fashion:
|
142
142
|
```ruby
|
143
143
|
class TodoItem < ActiveRecord::Base
|
144
|
-
|
144
|
+
belongs_to :todo_list
|
145
|
+
acts_as_list scope: [:task_category, :todo_list_id]
|
145
146
|
end
|
146
147
|
```
|
147
148
|
|
148
149
|
Furthermore, you can optionally include a hash of fixed parameters that will be included in all queries:
|
149
150
|
```ruby
|
150
151
|
class TodoItem < ActiveRecord::Base
|
151
|
-
|
152
|
+
belongs_to :todo_list
|
153
|
+
# or `discarded_at` if using discard
|
154
|
+
acts_as_list scope: [:task_category, :todo_list_id, deleted_at: nil]
|
152
155
|
end
|
153
156
|
```
|
154
157
|
|
155
|
-
This is useful when using this gem in conjunction with the popular [acts_as_paranoid](https://github.com/ActsAsParanoid/acts_as_paranoid)
|
158
|
+
This is useful when using this gem in conjunction with the popular [acts_as_paranoid](https://github.com/ActsAsParanoid/acts_as_paranoid) or [discard](https://github.com/jhawthorn/discard) gems.
|
156
159
|
|
157
160
|
## More Options
|
158
161
|
- `column`
|
data/gemfiles/rails_6_1.gemfile
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "http://rubygems.org"
|
4
|
+
|
5
|
+
gem "rake"
|
6
|
+
gem "appraisal"
|
7
|
+
gem "activerecord", "~> 7.0.0"
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem "github_changelog_generator", "~> 1.16.0"
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem "minitest", "~> 5.0"
|
15
|
+
gem "timecop"
|
16
|
+
gem "mocha"
|
17
|
+
end
|
18
|
+
|
19
|
+
group :sqlite do
|
20
|
+
gem "sqlite3", "~> 1.4"
|
21
|
+
end
|
22
|
+
|
23
|
+
group :postgresql do
|
24
|
+
gem "pg", "~> 1.3.0"
|
25
|
+
end
|
26
|
+
|
27
|
+
group :mysql do
|
28
|
+
gem "mysql2", "~> 0.5.0"
|
29
|
+
end
|
30
|
+
|
31
|
+
gemspec path: "../"
|
@@ -11,11 +11,9 @@ module ActiveRecord::Acts::List::CallbackDefiner #:nodoc:
|
|
11
11
|
before_update :check_scope, unless: :act_as_list_no_update?
|
12
12
|
after_update :update_positions, unless: :act_as_list_no_update?
|
13
13
|
|
14
|
-
|
14
|
+
after_save :clear_scope_changed
|
15
15
|
|
16
|
-
|
17
|
-
before_create "add_to_list_#{add_new_at}".to_sym, unless: :act_as_list_no_update?
|
18
|
-
end
|
16
|
+
before_create :avoid_collision, unless: :act_as_list_no_update?
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -229,36 +229,27 @@ module ActiveRecord
|
|
229
229
|
acts_as_list_class.default_scoped.unscope(:select, :where).where(scope_condition)
|
230
230
|
end
|
231
231
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
true
|
248
|
-
end
|
249
|
-
|
250
|
-
def add_to_list_bottom
|
251
|
-
if assume_default_position?
|
252
|
-
self[position_column] = bottom_position_in_list.to_i + 1
|
232
|
+
def avoid_collision
|
233
|
+
case add_new_at
|
234
|
+
when :top
|
235
|
+
if assume_default_position?
|
236
|
+
increment_positions_on_all_items
|
237
|
+
self[position_column] = acts_as_list_top
|
238
|
+
else
|
239
|
+
increment_positions_on_lower_items(self[position_column], id)
|
240
|
+
end
|
241
|
+
when :bottom
|
242
|
+
if assume_default_position?
|
243
|
+
self[position_column] = bottom_position_in_list.to_i + 1
|
244
|
+
else
|
245
|
+
increment_positions_on_lower_items(self[position_column], id)
|
246
|
+
end
|
253
247
|
else
|
254
|
-
increment_positions_on_lower_items(self[position_column], id)
|
248
|
+
increment_positions_on_lower_items(self[position_column], id) if position_changed
|
255
249
|
end
|
256
250
|
|
257
|
-
# Make sure we know that we've processed this scope change already
|
258
|
-
|
259
|
-
|
260
|
-
# Don't halt the callback chain
|
261
|
-
true
|
251
|
+
@scope_changed = false # Make sure we know that we've processed this scope change already
|
252
|
+
return true # Don't halt the callback chain
|
262
253
|
end
|
263
254
|
|
264
255
|
def assume_default_position?
|
@@ -454,7 +445,7 @@ module ActiveRecord
|
|
454
445
|
send('decrement_positions_on_lower_items') if lower_item
|
455
446
|
cached_changes.each { |attribute, values| send("#{attribute}=", values[1]) }
|
456
447
|
|
457
|
-
|
448
|
+
avoid_collision
|
458
449
|
end
|
459
450
|
end
|
460
451
|
|
data/lib/acts_as_list/version.rb
CHANGED
data/test/database.yml
CHANGED
@@ -4,13 +4,15 @@ sqlite:
|
|
4
4
|
|
5
5
|
mysql:
|
6
6
|
adapter: mysql2
|
7
|
+
host: 127.0.0.1
|
7
8
|
username: root
|
8
9
|
password:
|
9
10
|
database: acts_as_list
|
10
11
|
|
11
12
|
postgresql:
|
12
13
|
adapter: postgresql
|
14
|
+
host: localhost
|
13
15
|
username: postgres
|
14
|
-
password:
|
16
|
+
password: postgres
|
15
17
|
database: acts_as_list
|
16
18
|
min_messages: ERROR
|
data/test/shared_no_addition.rb
CHANGED
@@ -34,5 +34,40 @@ module Shared
|
|
34
34
|
new.reload
|
35
35
|
assert !new.in_list?
|
36
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
|
37
72
|
end
|
38
73
|
end
|
data/test/test_list.rb
CHANGED
@@ -604,6 +604,42 @@ class MultiDestroyTest < ActsAsListTestCase
|
|
604
604
|
end
|
605
605
|
end
|
606
606
|
|
607
|
+
class MultiUpdateTest < ActsAsListTestCase
|
608
|
+
|
609
|
+
def setup
|
610
|
+
setup_db
|
611
|
+
end
|
612
|
+
|
613
|
+
def test_multiple_updates_within_transaction
|
614
|
+
@page = ListMixin.create! id: 100, parent_id: nil, pos: 1
|
615
|
+
@row = ListMixin.create! parent_id: @page.id, pos: 1
|
616
|
+
@column1 = ListMixin.create! parent_id: @row.id, pos: 1
|
617
|
+
@column2 = ListMixin.create! parent_id: @row.id, pos: 2
|
618
|
+
@rich_text1 = ListMixin.create! parent_id: @column1.id, pos: 1
|
619
|
+
@rich_text2 = ListMixin.create! parent_id: @column2.id, pos: 1
|
620
|
+
|
621
|
+
ActiveRecord::Base.transaction do
|
622
|
+
@rich_text1.update!(parent_id: @column2.id, pos: 1)
|
623
|
+
|
624
|
+
assert_equal [@rich_text1.id, @rich_text2.id], ListMixin.where(parent_id: @column2.id).order('pos').map(&:id)
|
625
|
+
assert_equal [1, 2], ListMixin.where(parent_id: @column2.id).order('pos').map(&:pos)
|
626
|
+
|
627
|
+
@column1.destroy!
|
628
|
+
assert_equal [@column2.id], ListMixin.where(parent_id: @row.id).order('pos').map(&:id)
|
629
|
+
assert_equal [1], ListMixin.where(parent_id: @row.id).order('pos').map(&:pos)
|
630
|
+
|
631
|
+
@rich_text1.update!(parent_id: @page.id, pos: 1)
|
632
|
+
@rich_text2.update!(parent_id: @page.id, pos: 2)
|
633
|
+
@row.destroy!
|
634
|
+
@column2.destroy!
|
635
|
+
end
|
636
|
+
|
637
|
+
assert_equal(1, @page.reload.pos)
|
638
|
+
assert_equal [@rich_text1.id, @rich_text2.id], ListMixin.where(parent_id: @page.id).order('pos').map(&:id)
|
639
|
+
assert_equal [1, 2], ListMixin.where(parent_id: @page.id).order('pos').map(&:pos)
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
607
643
|
#class TopAdditionMixin < Mixin
|
608
644
|
|
609
645
|
class TopAdditionTest < ActsAsListTestCase
|
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: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Swanand Pagnis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-01-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -51,6 +51,8 @@ extra_rdoc_files: []
|
|
51
51
|
files:
|
52
52
|
- ".gemtest"
|
53
53
|
- ".github/FUNDING.yml"
|
54
|
+
- ".github/dependabot.yml"
|
55
|
+
- ".github/workflows/ci.yml"
|
54
56
|
- ".gitignore"
|
55
57
|
- ".travis.yml"
|
56
58
|
- Appraisals
|
@@ -66,6 +68,7 @@ files:
|
|
66
68
|
- gemfiles/rails_5_2.gemfile
|
67
69
|
- gemfiles/rails_6_0.gemfile
|
68
70
|
- gemfiles/rails_6_1.gemfile
|
71
|
+
- gemfiles/rails_7_0.gemfile
|
69
72
|
- init.rb
|
70
73
|
- lib/acts_as_list.rb
|
71
74
|
- lib/acts_as_list/active_record/acts/active_record.rb
|
@@ -118,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
121
|
- !ruby/object:Gem::Version
|
119
122
|
version: '0'
|
120
123
|
requirements: []
|
121
|
-
rubygems_version: 3.0.3
|
124
|
+
rubygems_version: 3.0.3.1
|
122
125
|
signing_key:
|
123
126
|
specification_version: 4
|
124
127
|
summary: A gem adding sorting, reordering capabilities to an active_record model,
|