paranoia 2.2.1 → 2.6.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 +5 -5
- data/.github/workflows/build.yml +61 -0
- data/CHANGELOG.md +114 -3
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +20 -8
- data/README.md +24 -0
- data/lib/paranoia/active_record_5_2.rb +41 -0
- data/lib/paranoia/rspec.rb +20 -17
- data/lib/paranoia/version.rb +1 -1
- data/lib/paranoia.rb +97 -40
- data/paranoia.gemspec +9 -4
- metadata +12 -12
- data/.travis.yml +0 -26
- data/test/paranoia_test.rb +0 -1273
data/lib/paranoia.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'active_record' unless defined? ActiveRecord
|
2
2
|
|
3
|
+
if [ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR] == [5, 2] ||
|
4
|
+
ActiveRecord::VERSION::MAJOR > 5
|
5
|
+
require 'paranoia/active_record_5_2'
|
6
|
+
end
|
7
|
+
|
3
8
|
module Paranoia
|
4
9
|
@@default_sentinel_value = nil
|
5
10
|
|
@@ -14,7 +19,6 @@ module Paranoia
|
|
14
19
|
|
15
20
|
def self.included(klazz)
|
16
21
|
klazz.extend Query
|
17
|
-
klazz.extend Callbacks
|
18
22
|
end
|
19
23
|
|
20
24
|
module Query
|
@@ -36,7 +40,7 @@ module Paranoia
|
|
36
40
|
# these will not match != sentinel value because "NULL != value" is
|
37
41
|
# NULL under the sql standard
|
38
42
|
# Scoping with the table_name is mandatory to avoid ambiguous errors when joining tables.
|
39
|
-
scoped_quoted_paranoia_column = "#{self.table_name}.#{connection.quote_column_name(paranoia_column)}"
|
43
|
+
scoped_quoted_paranoia_column = "#{connection.quote_table_name(self.table_name)}.#{connection.quote_column_name(paranoia_column)}"
|
40
44
|
with_deleted.where("#{scoped_quoted_paranoia_column} IS NULL OR #{scoped_quoted_paranoia_column} != ?", paranoia_sentinel_value)
|
41
45
|
end
|
42
46
|
alias_method :deleted, :only_deleted
|
@@ -53,30 +57,11 @@ module Paranoia
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
klazz.define_singleton_method("before_#{callback_name}") do |*args, &block|
|
62
|
-
set_callback(callback_name, :before, *args, &block)
|
63
|
-
end
|
64
|
-
|
65
|
-
klazz.define_singleton_method("around_#{callback_name}") do |*args, &block|
|
66
|
-
set_callback(callback_name, :around, *args, &block)
|
67
|
-
end
|
68
|
-
|
69
|
-
klazz.define_singleton_method("after_#{callback_name}") do |*args, &block|
|
70
|
-
set_callback(callback_name, :after, *args, &block)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def destroy
|
77
|
-
transaction do
|
78
|
-
run_callbacks(:destroy) do
|
79
|
-
result = delete
|
60
|
+
def paranoia_destroy
|
61
|
+
with_transaction_returning_status do
|
62
|
+
result = run_callbacks(:destroy) do
|
63
|
+
@_disable_counter_cache = deleted?
|
64
|
+
result = paranoia_delete
|
80
65
|
next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
|
81
66
|
each_counter_cached_associations do |association|
|
82
67
|
foreign_key = association.reflection.foreign_key.to_sym
|
@@ -84,12 +69,26 @@ module Paranoia
|
|
84
69
|
next unless send(association.reflection.name)
|
85
70
|
association.decrement_counters
|
86
71
|
end
|
72
|
+
@_trigger_destroy_callback = true
|
73
|
+
@_disable_counter_cache = false
|
87
74
|
result
|
88
75
|
end
|
89
|
-
|
76
|
+
raise ActiveRecord::Rollback, "Not destroyed" unless self.deleted?
|
77
|
+
result
|
78
|
+
end || false
|
79
|
+
end
|
80
|
+
alias_method :destroy, :paranoia_destroy
|
81
|
+
|
82
|
+
def paranoia_destroy!
|
83
|
+
paranoia_destroy ||
|
84
|
+
raise(ActiveRecord::RecordNotDestroyed.new("Failed to destroy the record", self))
|
90
85
|
end
|
91
86
|
|
92
|
-
def
|
87
|
+
def trigger_transactional_callbacks?
|
88
|
+
super || @_trigger_destroy_callback && paranoia_destroyed?
|
89
|
+
end
|
90
|
+
|
91
|
+
def paranoia_delete
|
93
92
|
raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
94
93
|
if persisted?
|
95
94
|
# if a transaction exists, add the record so that after_commit
|
@@ -101,18 +100,27 @@ module Paranoia
|
|
101
100
|
end
|
102
101
|
self
|
103
102
|
end
|
103
|
+
alias_method :delete, :paranoia_delete
|
104
104
|
|
105
105
|
def restore!(opts = {})
|
106
106
|
self.class.transaction do
|
107
107
|
run_callbacks(:restore) do
|
108
|
+
recovery_window_range = get_recovery_window_range(opts)
|
108
109
|
# Fixes a bug where the build would error because attributes were frozen.
|
109
110
|
# This only happened on Rails versions earlier than 4.1.
|
110
111
|
noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
|
111
|
-
if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
|
112
|
+
if within_recovery_window?(recovery_window_range) && ((noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen)
|
113
|
+
@_disable_counter_cache = !paranoia_destroyed?
|
112
114
|
write_attribute paranoia_column, paranoia_sentinel_value
|
113
115
|
update_columns(paranoia_restore_attributes)
|
116
|
+
each_counter_cached_associations do |association|
|
117
|
+
if send(association.reflection.name)
|
118
|
+
association.increment_counters
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@_disable_counter_cache = false
|
114
122
|
end
|
115
|
-
restore_associated_records if opts[:recursive]
|
123
|
+
restore_associated_records(recovery_window_range) if opts[:recursive]
|
116
124
|
end
|
117
125
|
end
|
118
126
|
|
@@ -120,14 +128,26 @@ module Paranoia
|
|
120
128
|
end
|
121
129
|
alias :restore :restore!
|
122
130
|
|
131
|
+
def get_recovery_window_range(opts)
|
132
|
+
return opts[:recovery_window_range] if opts[:recovery_window_range]
|
133
|
+
return unless opts[:recovery_window]
|
134
|
+
(deletion_time - opts[:recovery_window]..deletion_time + opts[:recovery_window])
|
135
|
+
end
|
136
|
+
|
137
|
+
def within_recovery_window?(recovery_window_range)
|
138
|
+
return true unless recovery_window_range
|
139
|
+
recovery_window_range.cover?(deletion_time)
|
140
|
+
end
|
141
|
+
|
123
142
|
def paranoia_destroyed?
|
124
|
-
|
143
|
+
paranoia_column_value != paranoia_sentinel_value
|
125
144
|
end
|
126
145
|
alias :deleted? :paranoia_destroyed?
|
127
146
|
|
128
147
|
def really_destroy!
|
129
|
-
|
148
|
+
with_transaction_returning_status do
|
130
149
|
run_callbacks(:real_destroy) do
|
150
|
+
@_disable_counter_cache = paranoia_destroyed?
|
131
151
|
dependent_reflections = self.class.reflections.select do |name, reflection|
|
132
152
|
reflection.options[:dependent] == :destroy
|
133
153
|
end
|
@@ -143,7 +163,7 @@ module Paranoia
|
|
143
163
|
association_data.really_destroy!
|
144
164
|
end
|
145
165
|
end
|
146
|
-
|
166
|
+
update_columns(paranoia_destroy_attributes)
|
147
167
|
destroy_without_paranoia
|
148
168
|
end
|
149
169
|
end
|
@@ -151,6 +171,10 @@ module Paranoia
|
|
151
171
|
|
152
172
|
private
|
153
173
|
|
174
|
+
def each_counter_cached_associations
|
175
|
+
!(defined?(@_disable_counter_cache) && @_disable_counter_cache) ? super : []
|
176
|
+
end
|
177
|
+
|
154
178
|
def paranoia_restore_attributes
|
155
179
|
{
|
156
180
|
paranoia_column => paranoia_sentinel_value
|
@@ -169,7 +193,7 @@ module Paranoia
|
|
169
193
|
|
170
194
|
# restore associated records that have been soft deleted when
|
171
195
|
# we called #destroy
|
172
|
-
def restore_associated_records
|
196
|
+
def restore_associated_records(recovery_window_range = nil)
|
173
197
|
destroyed_associations = self.class.reflect_on_all_associations.select do |association|
|
174
198
|
association.options[:dependent] == :destroy
|
175
199
|
end
|
@@ -180,9 +204,11 @@ module Paranoia
|
|
180
204
|
unless association_data.nil?
|
181
205
|
if association_data.paranoid?
|
182
206
|
if association.collection?
|
183
|
-
association_data.only_deleted.each
|
207
|
+
association_data.only_deleted.each do |record|
|
208
|
+
record.restore(:recursive => true, :recovery_window_range => recovery_window_range)
|
209
|
+
end
|
184
210
|
else
|
185
|
-
association_data.restore(:recursive => true)
|
211
|
+
association_data.restore(:recursive => true, :recovery_window_range => recovery_window_range)
|
186
212
|
end
|
187
213
|
end
|
188
214
|
end
|
@@ -200,18 +226,32 @@ module Paranoia
|
|
200
226
|
|
201
227
|
association_class = association_class_name.constantize
|
202
228
|
if association_class.paranoid?
|
203
|
-
association_class.only_deleted.where(association_find_conditions).first
|
229
|
+
association_class.only_deleted.where(association_find_conditions).first
|
230
|
+
.try!(:restore, recursive: true, :recovery_window_range => recovery_window_range)
|
204
231
|
end
|
205
232
|
end
|
206
233
|
end
|
207
234
|
|
208
|
-
|
235
|
+
if ActiveRecord.version.to_s > '7'
|
236
|
+
# Method deleted in https://github.com/rails/rails/commit/dd5886d00a2d5f31ccf504c391aad93deb014eb8
|
237
|
+
@association_cache.clear if persisted? && destroyed_associations.present?
|
238
|
+
else
|
239
|
+
clear_association_cache if destroyed_associations.present?
|
240
|
+
end
|
209
241
|
end
|
210
242
|
end
|
211
243
|
|
212
244
|
ActiveSupport.on_load(:active_record) do
|
213
245
|
class ActiveRecord::Base
|
214
246
|
def self.acts_as_paranoid(options={})
|
247
|
+
if included_modules.include?(Paranoia)
|
248
|
+
puts "[WARN] #{self.name} is calling acts_as_paranoid more than once!"
|
249
|
+
|
250
|
+
return
|
251
|
+
end
|
252
|
+
|
253
|
+
define_model_callbacks :restore, :real_destroy
|
254
|
+
|
215
255
|
alias_method :really_destroyed?, :destroyed?
|
216
256
|
alias_method :really_delete, :delete
|
217
257
|
alias_method :destroy_without_paranoia, :destroy
|
@@ -258,9 +298,17 @@ ActiveSupport.on_load(:active_record) do
|
|
258
298
|
self.class.paranoia_column
|
259
299
|
end
|
260
300
|
|
301
|
+
def paranoia_column_value
|
302
|
+
send(paranoia_column)
|
303
|
+
end
|
304
|
+
|
261
305
|
def paranoia_sentinel_value
|
262
306
|
self.class.paranoia_sentinel_value
|
263
307
|
end
|
308
|
+
|
309
|
+
def deletion_time
|
310
|
+
paranoia_column_value.acts_like?(:time) ? paranoia_column_value : deleted_at
|
311
|
+
end
|
264
312
|
end
|
265
313
|
end
|
266
314
|
|
@@ -269,8 +317,8 @@ require 'paranoia/rspec' if defined? RSpec
|
|
269
317
|
module ActiveRecord
|
270
318
|
module Validations
|
271
319
|
module UniquenessParanoiaValidator
|
272
|
-
def build_relation(klass,
|
273
|
-
relation = super
|
320
|
+
def build_relation(klass, *args)
|
321
|
+
relation = super
|
274
322
|
return relation unless klass.respond_to?(:paranoia_column)
|
275
323
|
arel_paranoia_scope = klass.arel_table[klass.paranoia_column].eq(klass.paranoia_sentinel_value)
|
276
324
|
if ActiveRecord::VERSION::STRING >= "5.0"
|
@@ -284,5 +332,14 @@ module ActiveRecord
|
|
284
332
|
class UniquenessValidator < ActiveModel::EachValidator
|
285
333
|
prepend UniquenessParanoiaValidator
|
286
334
|
end
|
335
|
+
|
336
|
+
class AssociationNotSoftDestroyedValidator < ActiveModel::EachValidator
|
337
|
+
def validate_each(record, attribute, value)
|
338
|
+
# if association is soft destroyed, add an error
|
339
|
+
if value.present? && value.paranoia_destroyed?
|
340
|
+
record.errors.add(attribute, 'has been soft-deleted')
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
287
344
|
end
|
288
345
|
end
|
data/paranoia.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.license = 'MIT'
|
12
12
|
s.summary = "Paranoia is a re-implementation of acts_as_paranoid for Rails 3, 4, and 5, using much, much, much less code."
|
13
13
|
s.description = <<-DSC
|
14
|
-
Paranoia is a re-implementation of acts_as_paranoid for Rails
|
14
|
+
Paranoia is a re-implementation of acts_as_paranoid for Rails 4, 5, 6, and 7,
|
15
15
|
using much, much, much less code. You would use either plugin / gem if you
|
16
16
|
wished that when you called destroy on an Active Record object that it
|
17
17
|
didn't actually destroy it, but just "hid" the record. Paranoia does this
|
@@ -22,14 +22,19 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.required_rubygems_version = ">= 1.3.6"
|
24
24
|
|
25
|
-
s.required_ruby_version = '>= 2.
|
25
|
+
s.required_ruby_version = '>= 2.5'
|
26
26
|
|
27
|
-
s.add_dependency 'activerecord', '>=
|
27
|
+
s.add_dependency 'activerecord', '>= 5.1', '< 7.1'
|
28
28
|
|
29
29
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
30
30
|
s.add_development_dependency "rake"
|
31
31
|
|
32
|
-
|
32
|
+
|
33
|
+
s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
34
|
+
files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)}) }
|
35
|
+
files
|
36
|
+
end
|
37
|
+
|
33
38
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
34
39
|
s.require_path = 'lib'
|
35
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paranoia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radarlistener@gmail.com
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.1'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '5.1'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: bundler
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,7 +59,7 @@ dependencies:
|
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
61
|
description: |2
|
62
|
-
Paranoia is a re-implementation of acts_as_paranoid for Rails
|
62
|
+
Paranoia is a re-implementation of acts_as_paranoid for Rails 4, 5, 6, and 7,
|
63
63
|
using much, much, much less code. You would use either plugin / gem if you
|
64
64
|
wished that when you called destroy on an Active Record object that it
|
65
65
|
didn't actually destroy it, but just "hid" the record. Paranoia does this
|
@@ -73,19 +73,20 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- ".github/workflows/build.yml"
|
76
77
|
- ".gitignore"
|
77
|
-
- ".travis.yml"
|
78
78
|
- CHANGELOG.md
|
79
|
+
- CODE_OF_CONDUCT.md
|
79
80
|
- CONTRIBUTING.md
|
80
81
|
- Gemfile
|
81
82
|
- LICENSE
|
82
83
|
- README.md
|
83
84
|
- Rakefile
|
84
85
|
- lib/paranoia.rb
|
86
|
+
- lib/paranoia/active_record_5_2.rb
|
85
87
|
- lib/paranoia/rspec.rb
|
86
88
|
- lib/paranoia/version.rb
|
87
89
|
- paranoia.gemspec
|
88
|
-
- test/paranoia_test.rb
|
89
90
|
homepage: https://github.com/rubysherpas/paranoia
|
90
91
|
licenses:
|
91
92
|
- MIT
|
@@ -98,15 +99,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
99
|
requirements:
|
99
100
|
- - ">="
|
100
101
|
- !ruby/object:Gem::Version
|
101
|
-
version: '2.
|
102
|
+
version: '2.5'
|
102
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
104
|
requirements:
|
104
105
|
- - ">="
|
105
106
|
- !ruby/object:Gem::Version
|
106
107
|
version: 1.3.6
|
107
108
|
requirements: []
|
108
|
-
|
109
|
-
rubygems_version: 2.6.9
|
109
|
+
rubygems_version: 3.1.6
|
110
110
|
signing_key:
|
111
111
|
specification_version: 4
|
112
112
|
summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, 4, and 5,
|
data/.travis.yml
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
cache: bundler
|
4
|
-
rvm:
|
5
|
-
- 2.1.10
|
6
|
-
- 2.2.6
|
7
|
-
- 2.3.3
|
8
|
-
- jruby-9.1.6.0
|
9
|
-
|
10
|
-
env:
|
11
|
-
matrix:
|
12
|
-
- RAILS='~> 4.1.16'
|
13
|
-
- RAILS='~> 4.2.7.1'
|
14
|
-
- RAILS='~> 5.0.0.1'
|
15
|
-
|
16
|
-
matrix:
|
17
|
-
exclude:
|
18
|
-
- env: RAILS='~> 5.0.0.1'
|
19
|
-
rvm: 2.1.10
|
20
|
-
allow_failures:
|
21
|
-
- env: RAILS='~> 4.1.16'
|
22
|
-
rvm: jruby-9.1.6.0
|
23
|
-
- env: RAILS='~> 4.2.7.1'
|
24
|
-
rvm: jruby-9.1.6.0
|
25
|
-
- env: RAILS='~> 5.0.0.1'
|
26
|
-
rvm: jruby-9.1.6.0
|