acts_as_list 1.0.4 → 1.1.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
  SHA256:
3
- metadata.gz: a36b9ed8db57946d5ac96c829c68ce4f4107068628827840140e9dadb3c682fa
4
- data.tar.gz: 60b6890922d26b913aed5a212eae7d228629c1ce3721dd0818ec2e5069697d25
3
+ metadata.gz: ece77b4a7a9c6c50d1d7a188c91c6dedd4c1dba4c8ece714c2922b339c3b5490
4
+ data.tar.gz: e7d925c76332e504d6a3db3706c4362b962d5bef2f9c882023bef99a0763e2d1
5
5
  SHA512:
6
- metadata.gz: 1bfced5d2dd4e50194eb8bdb92b244d40dd0a19df0ee663649510a965077a0d332715dc0100c1e9d006222e96e57745638c77812767b88ec7b9274dd350af4c1
7
- data.tar.gz: 485f6be53763f1f112095075b1c69d6e620f89018c2e3435f3500decf986e110c832f78ce5db6462d6233d13816516a2c1d59df1e3c172455439a11704b1c8b5
6
+ metadata.gz: 8ca617673d046ef18baab0a51d4e481ac10e7b044c569a9efb201c894be702aec66eb72cbc5364bb85b6374c144990fcc3c367b01cc62e0f431d87b6e41e0f4f
7
+ data.tar.gz: c1ce411f1aa503b28a837b714db52a4bcb42ae78542183f6641aa0d0f483c9c98b3521a4557554e9de539b12effeee6f901632636d61408e423c55d67287f47b
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -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
@@ -36,5 +36,9 @@ appraise "rails-6-0" do
36
36
  end
37
37
 
38
38
  appraise "rails-6-1" do
39
- gem "activerecord", "6.1.0.rc1"
39
+ gem "activerecord", "~> 6.1.0"
40
+ end
41
+
42
+ appraise "rails-7-0" do
43
+ gem "activerecord", "~> 7.0.0"
40
44
  end
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
- # `kind` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
137
- acts_as_list scope: [:kind]
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
- acts_as_list scope: [:kind, :owner_id]
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
- acts_as_list scope: [:kind, :owner_id, deleted_at: nil]
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) gem.
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`
@@ -4,7 +4,7 @@ source "http://rubygems.org"
4
4
 
5
5
  gem "rake"
6
6
  gem "appraisal"
7
- gem "activerecord", "6.1.0.rc1"
7
+ gem "activerecord", "~> 6.1.0"
8
8
 
9
9
  group :development do
10
10
  gem "github_changelog_generator", "1.9.0"
@@ -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
- after_commit :clear_scope_changed
14
+ after_save :clear_scope_changed
15
15
 
16
- if add_new_at.present?
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
- # Poorly named methods. They will insert the item at the desired position if the position
233
- # has been set manually using position=, not necessarily the top or bottom of the list:
234
-
235
- def add_to_list_top
236
- if assume_default_position?
237
- increment_positions_on_all_items
238
- self[position_column] = acts_as_list_top
239
- else
240
- increment_positions_on_lower_items(self[position_column], id)
241
- end
242
-
243
- # Make sure we know that we've processed this scope change already
244
- @scope_changed = false
245
-
246
- # Don't halt the callback chain
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
- @scope_changed = false
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
- send("add_to_list_#{add_new_at}") if add_new_at.present?
448
+ avoid_collision
458
449
  end
459
450
  end
460
451
 
@@ -3,7 +3,7 @@
3
3
  module ActiveRecord
4
4
  module Acts
5
5
  module List
6
- VERSION = '1.0.4'
6
+ VERSION = '1.1.0'
7
7
  end
8
8
  end
9
9
  end
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
@@ -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
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: 2021-04-19 00:00:00.000000000 Z
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,