Skip to content

Commit 7a00247

Browse files
authored
Merge branch 'core' into fix-nil-error-on-dependency-handling
2 parents b61e83b + f441c37 commit 7a00247

File tree

7 files changed

+120
-56
lines changed

7 files changed

+120
-56
lines changed

Diff for: .github/workflows/build.yml

+14-25
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,24 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
rails: ["~> 7.0.0", "~> 6.1.0", "~> 6.0.0"]
19-
ruby: ["3.2.2", "3.1.4", "3.0.6", "2.7.8"]
20-
include:
21-
- ruby: 3.2
22-
rails: 'edge'
23-
# single test failure with jruby
24-
#- ruby: jruby-9.4
25-
# rails: '~> 7.0.0'
26-
- ruby: 2.6
27-
rails: '~> 6.1.0'
28-
- ruby: 2.6
29-
rails: '~> 6.0.0'
30-
- ruby: 2.6
31-
rails: '~> 5.2.0'
32-
- ruby: 2.6
33-
rails: '~> 5.1.0'
34-
- ruby: 2.5
35-
rails: '~> 6.0.0'
36-
- ruby: 2.5
37-
rails: '~> 5.2.0'
38-
- ruby: 2.5
39-
rails: '~> 5.1.0'
40-
#os: ubuntu-latest
41-
#arch: x64
18+
rails: ["edge", "~> 7.2.0", "~> 7.1.0", "~> 7.0.0", "~> 6.1.0"]
19+
ruby: ["3.3","3.2", "3.1", "3.0", "2.7"]
20+
exclude:
21+
- rails: "~> 7.2.0"
22+
ruby: "3.0"
23+
- rails: "~> 7.2.0"
24+
ruby: "2.7"
25+
- rails: "edge"
26+
ruby: "3.0"
27+
- rails: "edge"
28+
ruby: "2.7"
29+
30+
4231

4332
env:
4433
RAILS: ${{ matrix.rails }}
4534
steps:
46-
- uses: actions/checkout@v2
35+
- uses: actions/checkout@v4
4736
- uses: ruby/setup-ruby@v1
4837
with:
4938
ruby-version: ${{ matrix.ruby }}

Diff for: CHANGELOG.md

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,37 @@
11
# paranoia Changelog
22

3-
## 2.6.2
3+
## 3.0.0 - August 13, 2024
44

5-
* [#441](https://github.com/rubysherpas/paranoia/pull/441) Recursive restore with has_many/one through assocs (#441)
5+
_Tagged as 3.0 as Ruby + Rails version constraints have been modernised._
6+
7+
- [#564](https://github.com/rubysherpas/paranoia/pull/564) Support Rails edge
8+
- [#563](https://github.com/rubysherpas/paranoia/pull/563) Support Rails 7.2
9+
10+
## 2.6.4 - July 20, 2024
11+
12+
* [#554](https://github.com/rubysherpas/paranoia/pull/554) Support prebuilt counter cache association list (#554)
13+
[Joé Dupuis](https://github.com/JoeDupuis)
14+
* [#551](https://github.com/rubysherpas/paranoia/pull/551) Fix: restore has_one with scope (#551)
15+
[Paweł Charyło](https://github.com/zygzagZ)
16+
* [#555](https://github.com/rubysherpas/paranoia/pull/555) 📝 Add Yard documentation for Paranoia::Query (#555)
17+
[Clément Prod'homme](https://github.com/cprodhomme)
18+
19+
## 2.6.3 - Oct 12, 2023
20+
21+
* [#548](https://github.com/rubysherpas/paranoia/pull/548) Add support for [Rails 7.1](https://github.com/rails/rails/releases/tag/v7.1.0) (#548)
22+
[Indyarocks](https://github.com/indyarocks)
23+
24+
## 2.6.2 - Jun 6, 2023
25+
26+
* [#441](https://github.com/rubysherpas/paranoia/pull/441) Recursive restore with has_many/one through assocs (#441)
627
[Emil Ong](https://github.com/emilong)
728

8-
## 2.6.1
29+
## 2.6.1 - Nov 16, 2022
930

1031
* [#535](https://github.com/rubysherpas/paranoia/pull/535) Allow to skip updating paranoia_destroy_attributes for records while really_destroy!
1132
[Anton Bogdanov](https://github.com/kortirso)
1233

13-
## 2.6.0
34+
## 2.6.0 - Mar 23, 2022
1435

1536
* [#512](https://github.com/rubysherpas/paranoia/pull/512) Quote table names; Mysql 8 has keywords that might match table names which cause an exception.
1637
* [#476](https://github.com/rubysherpas/paranoia/pull/476) Fix syntax error in documentation.

Diff for: Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sqlite = ENV['SQLITE_VERSION']
55
if sqlite
66
gem 'sqlite3', sqlite, platforms: [:ruby]
77
else
8-
gem 'sqlite3', platforms: [:ruby]
8+
gem 'sqlite3', '~> 1.4', platforms: [:ruby]
99
end
1010

1111
platforms :jruby do

Diff for: lib/paranoia.rb

+35-21
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ def self.included(klazz)
2424
module Query
2525
def paranoid? ; true ; end
2626

27+
# If you want to find all records, even those which are deleted
2728
def with_deleted
2829
if ActiveRecord::VERSION::STRING >= "4.1"
2930
return unscope where: paranoia_column
3031
end
3132
all.tap { |x| x.default_scoped = false }
3233
end
3334

35+
# If you want to find only the deleted records
3436
def only_deleted
3537
if paranoia_sentinel_value.nil?
3638
return with_deleted.where.not(paranoia_column => paranoia_sentinel_value)
@@ -45,6 +47,7 @@ def only_deleted
4547
end
4648
alias_method :deleted, :only_deleted
4749

50+
# If you want to restore a record
4851
def restore(id_or_ids, opts = {})
4952
ids = Array(id_or_ids).flatten
5053
any_object_instead_of_id = ids.any? { |id| ActiveRecord::Base === id }
@@ -60,7 +63,7 @@ def restore(id_or_ids, opts = {})
6063
def paranoia_destroy
6164
with_transaction_returning_status do
6265
result = run_callbacks(:destroy) do
63-
@_disable_counter_cache = deleted?
66+
@_disable_counter_cache = paranoia_destroyed?
6467
result = paranoia_delete
6568
next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
6669
each_counter_cached_associations do |association|
@@ -73,7 +76,7 @@ def paranoia_destroy
7376
@_disable_counter_cache = false
7477
result
7578
end
76-
raise ActiveRecord::Rollback, "Not destroyed" unless self.deleted?
79+
raise ActiveRecord::Rollback, "Not destroyed" unless paranoia_destroyed?
7780
result
7881
end || false
7982
end
@@ -173,8 +176,25 @@ def really_destroy!(update_destroy_attributes: true)
173176

174177
private
175178

179+
def counter_cache_disabled?
180+
defined?(@_disable_counter_cache) && @_disable_counter_cache
181+
end
182+
183+
def counter_cached_association_names
184+
return [] if counter_cache_disabled?
185+
super
186+
end
187+
176188
def each_counter_cached_associations
177-
!(defined?(@_disable_counter_cache) && @_disable_counter_cache) ? super : []
189+
return [] if counter_cache_disabled?
190+
191+
if defined?(super)
192+
super
193+
else
194+
counter_cached_association_names.each do |name|
195+
yield association(name)
196+
end
197+
end
178198
end
179199

180200
def paranoia_restore_attributes
@@ -193,6 +213,16 @@ def timestamp_attributes_with_current_time
193213
timestamp_attributes_for_update_in_model.each_with_object({}) { |attr,hash| hash[attr] = current_time_from_proper_timezone }
194214
end
195215

216+
def paranoia_find_has_one_target(association)
217+
association_foreign_key = association.options[:through].present? ? association.klass.primary_key : association.foreign_key
218+
association_find_conditions = { association_foreign_key => self.id }
219+
association_find_conditions[association.type] = self.class.name if association.type
220+
221+
scope = association.klass.only_deleted.where(association_find_conditions)
222+
scope = scope.merge(association.scope) if association.scope
223+
scope.first
224+
end
225+
196226
# restore associated records that have been soft deleted when
197227
# we called #destroy
198228
def restore_associated_records(recovery_window_range = nil)
@@ -216,24 +246,8 @@ def restore_associated_records(recovery_window_range = nil)
216246
end
217247

218248
if association_data.nil? && association.macro.to_s == "has_one"
219-
association_class_name = association.klass.name
220-
221-
association_foreign_key = if association.options[:through].present?
222-
association.klass.primary_key
223-
else
224-
association.foreign_key
225-
end
226-
227-
if association.type
228-
association_polymorphic_type = association.type
229-
association_find_conditions = { association_polymorphic_type => self.class.name.to_s, association_foreign_key => self.id }
230-
else
231-
association_find_conditions = { association_foreign_key => self.id }
232-
end
233-
234-
association_class = association.klass
235-
if association_class.paranoid?
236-
association_class.only_deleted.where(association_find_conditions).first
249+
if association.klass.paranoid?
250+
paranoia_find_has_one_target(association)
237251
.try!(:restore, recursive: true, :recovery_window_range => recovery_window_range)
238252
end
239253
end

Diff for: lib/paranoia/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Paranoia
2-
VERSION = '2.6.2'.freeze
2+
VERSION = '3.0.0'.freeze
33
end

Diff for: paranoia.gemspec

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
1111
s.license = 'MIT'
1212
s.summary = "Paranoia is a re-implementation of acts_as_paranoid for Rails 3, 4, and 5, using much, much, much less code."
1313
s.description = <<-DSC
14-
Paranoia is a re-implementation of acts_as_paranoid for Rails 4, 5, 6, and 7,
14+
Paranoia is a re-implementation of acts_as_paranoid for Rails 5, 6, and 7,
1515
using much, much, much less code. You would use either plugin / gem if you
1616
wished that when you called destroy on an Active Record object that it
1717
didn't actually destroy it, but just "hid" the record. Paranoia does this
@@ -22,9 +22,9 @@ Gem::Specification.new do |s|
2222

2323
s.required_rubygems_version = ">= 1.3.6"
2424

25-
s.required_ruby_version = '>= 2.5'
25+
s.required_ruby_version = '>= 2.7'
2626

27-
s.add_dependency 'activerecord', '>= 5.1', '< 7.1'
27+
s.add_dependency 'activerecord', '>= 6', '< 8.1'
2828

2929
s.add_development_dependency "bundler", ">= 1.0.0"
3030
s.add_development_dependency "rake"

Diff for: test/paranoia_test.rb

+41-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require 'minitest/autorun'
44
require 'paranoia'
55

6-
test_framework = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
6+
test_framework = defined?(Minitest::Test) ? Minitest::Test : Minitest::Unit::TestCase
77

88
if ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks=)
99
ActiveRecord::Base.raise_in_transactional_callbacks = true
@@ -54,6 +54,7 @@ def setup!
5454
'empty_paranoid_models' => 'deleted_at DATETIME',
5555
'paranoid_has_one_throughs' => 'paranoid_has_through_restore_parent_id INTEGER NOT NULL, empty_paranoid_model_id INTEGER NOT NULL, deleted_at DATETIME',
5656
'paranoid_has_many_throughs' => 'paranoid_has_through_restore_parent_id INTEGER NOT NULL, empty_paranoid_model_id INTEGER NOT NULL, deleted_at DATETIME',
57+
'paranoid_has_one_with_scopes' => 'deleted_at DATETIME, kind STRING, paranoid_has_one_with_scope_id INTEGER',
5758
}.each do |table_name, columns_as_sql_string|
5859
ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
5960
end
@@ -1223,6 +1224,37 @@ def test_counter_cache_column_on_restore
12231224
end
12241225
end
12251226

1227+
def test_has_one_with_scope_missed
1228+
parent = ParanoidHasOneWithScope.create
1229+
gamma = ParanoidHasOneWithScope.create(kind: :gamma, paranoid_has_one_with_scope: parent) # this has to be first
1230+
alpha = ParanoidHasOneWithScope.create(kind: :alpha, paranoid_has_one_with_scope: parent)
1231+
beta = ParanoidHasOneWithScope.create(kind: :beta, paranoid_has_one_with_scope: parent)
1232+
1233+
parent.destroy
1234+
assert !gamma.reload.destroyed?
1235+
gamma.destroy
1236+
assert_equal 0, ParanoidHasOneWithScope.count # all destroyed
1237+
parent.reload # we unload associations
1238+
parent.restore(recursive: true)
1239+
1240+
assert_equal "alpha", parent.alpha&.kind, "record was not restored"
1241+
assert_equal "beta", parent.beta&.kind, "record was not restored"
1242+
assert_nil parent.gamma, "record was incorrectly restored"
1243+
end
1244+
1245+
def test_has_one_with_scope_not_restored
1246+
parent = ParanoidHasOneWithScope.create
1247+
gamma = ParanoidHasOneWithScope.create(kind: :gamma, paranoid_has_one_with_scope: parent)
1248+
parent.destroy
1249+
assert_equal 1, ParanoidHasOneWithScope.count # gamma not deleted
1250+
gamma.destroy
1251+
parent.reload # we unload associations
1252+
parent.restore(recursive: true)
1253+
1254+
assert gamma.reload.deleted?, "the record was incorrectly restored"
1255+
assert_equal 1, ParanoidHasOneWithScope.count # gamma deleted
1256+
end
1257+
12261258
private
12271259
def get_featureful_model
12281260
FeaturefulModel.new(:name => "not empty")
@@ -1627,3 +1659,11 @@ class ParanoidHasManyThrough < ActiveRecord::Base
16271659
belongs_to :paranoid_has_through_restore_parent
16281660
belongs_to :empty_paranoid_model, dependent: :destroy
16291661
end
1662+
1663+
class ParanoidHasOneWithScope < ActiveRecord::Base
1664+
acts_as_paranoid
1665+
has_one :alpha, -> () { where(kind: :alpha) }, class_name: "ParanoidHasOneWithScope", dependent: :destroy
1666+
has_one :beta, -> () { where(kind: :beta) }, class_name: "ParanoidHasOneWithScope", dependent: :destroy
1667+
has_one :gamma, -> () { where(kind: :gamma) }, class_name: "ParanoidHasOneWithScope"
1668+
belongs_to :paranoid_has_one_with_scope
1669+
end

0 commit comments

Comments
 (0)