paranoia 1.3.3 → 1.3.4
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/README.md +5 -4
- data/lib/paranoia.rb +41 -9
- data/lib/paranoia/rspec.rb +13 -0
- data/lib/paranoia/version.rb +1 -1
- data/paranoia.gemspec +1 -1
- data/test/paranoia_test.rb +102 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bf4edf194a7572da8b0edc79105f4c62a37bfd2
|
4
|
+
data.tar.gz: dd084504c6c843de8ab3f7970570db894feac1ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9162181a3e8261387eefdfa78a512c0eee6fef54d19e2455673cb4b96f1fd673b8531b3357a1501967360610ae7b0cefecbe75cee06ae732af331639e7012535
|
7
|
+
data.tar.gz: 66b30b12969246dc8c820c32bc4a4df0f817ffa00ab99a48fcd152e9e9fcf503f5d1a2dce271b154bd11a15d3c1a61a39a6678c520036f006d900e79215cc396
|
data/README.md
CHANGED
@@ -4,9 +4,9 @@ Paranoia is a re-implementation of [acts\_as\_paranoid](http://github.com/techno
|
|
4
4
|
|
5
5
|
You would use either plugin / gem if you wished that when you called `destroy` on an Active Record object that it didn't actually destroy it, but just "hid" the record. Paranoia does this by setting a `deleted_at` field to the current time when you `destroy` a record, and hides it by scoping all queries on your model to only include records which do not have a `deleted_at` field.
|
6
6
|
|
7
|
-
If you wish to actually destroy an object you may call
|
7
|
+
If you wish to actually destroy an object you may call `really_destroy!`. **WARNING**: This will also *really destroy* all `dependent: destroy` records, so please aim this method away from face when using.**
|
8
8
|
|
9
|
-
If a record has `has_many` associations defined AND those associations have `dependent: :destroy` set on them, then they will also be soft-deleted
|
9
|
+
If a record has `has_many` associations defined AND those associations have `dependent: :destroy` set on them, then they will also be soft-deleted if ``acts_as_paranoid`` is set, otherwise the normal destroy will be called.
|
10
10
|
|
11
11
|
## Installation & Usage
|
12
12
|
|
@@ -25,7 +25,7 @@ gem 'paranoia', '~> 2.0'
|
|
25
25
|
Of course you can install this from GitHub as well:
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
gem 'paranoia', :github => 'radar/paranoia', :branch => '
|
28
|
+
gem 'paranoia', :github => 'radar/paranoia', :branch => 'rails3'
|
29
29
|
# or
|
30
30
|
gem 'paranoia', :github => 'radar/paranoia', :branch => 'rails4'
|
31
31
|
```
|
@@ -43,7 +43,7 @@ Updating is as simple as `bundle update paranoia`.
|
|
43
43
|
Run:
|
44
44
|
|
45
45
|
```shell
|
46
|
-
rails generate migration AddDeletedAtToClients deleted_at:datetime
|
46
|
+
rails generate migration AddDeletedAtToClients deleted_at:datetime:index
|
47
47
|
```
|
48
48
|
|
49
49
|
and now you have a migration
|
@@ -52,6 +52,7 @@ and now you have a migration
|
|
52
52
|
class AddDeletedAtToClients < ActiveRecord::Migration
|
53
53
|
def change
|
54
54
|
add_column :clients, :deleted_at, :datetime
|
55
|
+
add_index :clients, :deleted_at
|
55
56
|
end
|
56
57
|
end
|
57
58
|
```
|
data/lib/paranoia.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_record' unless defined? ActiveRecord
|
2
|
+
|
1
3
|
module Paranoia
|
2
4
|
def self.included(klazz)
|
3
5
|
klazz.extend Query
|
@@ -47,7 +49,8 @@ module Paranoia
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def destroy
|
50
|
-
run_callbacks(:destroy) { touch_paranoia_column(true) }
|
52
|
+
callbacks_result = run_callbacks(:destroy) { touch_paranoia_column(true) }
|
53
|
+
callbacks_result ? self : false
|
51
54
|
end
|
52
55
|
|
53
56
|
def delete
|
@@ -77,10 +80,15 @@ module Paranoia
|
|
77
80
|
# insert time to paranoia column.
|
78
81
|
# @param with_transaction [Boolean] exec with ActiveRecord Transactions.
|
79
82
|
def touch_paranoia_column(with_transaction=false)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
83
|
+
# This method is (potentially) called from really_destroy
|
84
|
+
# The object the method is being called on may be frozen
|
85
|
+
# Let's not touch it if it's frozen.
|
86
|
+
unless self.frozen?
|
87
|
+
if with_transaction
|
88
|
+
with_transaction_returning_status { touch(paranoia_column) }
|
89
|
+
else
|
90
|
+
touch(paranoia_column)
|
91
|
+
end
|
84
92
|
end
|
85
93
|
end
|
86
94
|
|
@@ -92,10 +100,16 @@ module Paranoia
|
|
92
100
|
end
|
93
101
|
|
94
102
|
destroyed_associations.each do |association|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
103
|
+
association_data = send(association.name)
|
104
|
+
|
105
|
+
unless association_data.nil?
|
106
|
+
if association_data.paranoid?
|
107
|
+
if association.collection?
|
108
|
+
association_data.only_deleted.each { |record| record.restore(:recursive => true) }
|
109
|
+
else
|
110
|
+
association_data.restore(:recursive => true)
|
111
|
+
end
|
112
|
+
end
|
99
113
|
end
|
100
114
|
end
|
101
115
|
end
|
@@ -103,9 +117,25 @@ end
|
|
103
117
|
|
104
118
|
class ActiveRecord::Base
|
105
119
|
def self.acts_as_paranoid(options={})
|
120
|
+
alias :really_destroyed? :destroyed?
|
106
121
|
alias :ar_destroy :destroy
|
107
122
|
alias :destroy! :ar_destroy
|
108
123
|
alias :delete! :delete
|
124
|
+
def really_destroy!
|
125
|
+
dependent_reflections = self.reflections.select do |name, reflection|
|
126
|
+
reflection.options[:dependent] == :destroy
|
127
|
+
end
|
128
|
+
if dependent_reflections.any?
|
129
|
+
dependent_reflections.each do |name, _|
|
130
|
+
associated_records = self.send(name)
|
131
|
+
# Paranoid models will have this method, non-paranoid models will not
|
132
|
+
associated_records = associated_records.with_deleted if associated_records.respond_to?(:with_deleted)
|
133
|
+
associated_records.each(&:really_destroy!)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
destroy!
|
137
|
+
end
|
138
|
+
|
109
139
|
include Paranoia
|
110
140
|
class_attribute :paranoia_column
|
111
141
|
|
@@ -141,3 +171,5 @@ class ActiveRecord::Base
|
|
141
171
|
self.class.paranoia_column
|
142
172
|
end
|
143
173
|
end
|
174
|
+
|
175
|
+
require 'paranoia/rspec' if defined? RSpec
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
# Validate the subject's class did call "acts_as_paranoid"
|
4
|
+
RSpec::Matchers.define :act_as_paranoid do
|
5
|
+
match { |subject| subject.class.ancestors.include?(Paranoia) }
|
6
|
+
|
7
|
+
failure_message { "expected #{subject.class} to use `acts_as_paranoid`" }
|
8
|
+
failure_message_when_negated { "expected #{subject.class} not to use `acts_as_paranoid`" }
|
9
|
+
|
10
|
+
# RSpec 2 compatibility:
|
11
|
+
alias_method :failure_message_for_should, :failure_message
|
12
|
+
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
13
|
+
end
|
data/lib/paranoia/version.rb
CHANGED
data/paranoia.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.required_rubygems_version = '>= 1.3.6'
|
15
15
|
s.rubyforge_project = 'paranoia'
|
16
16
|
|
17
|
-
s.add_dependency 'activerecord', '~> 3.
|
17
|
+
s.add_dependency 'activerecord', '~> 3.1'
|
18
18
|
|
19
19
|
s.add_development_dependency 'bundler', '>= 1.0.0'
|
20
20
|
s.add_development_dependency 'rake'
|
data/test/paranoia_test.rb
CHANGED
@@ -10,9 +10,11 @@ FileUtils.rm_f DB_FILE
|
|
10
10
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => DB_FILE
|
11
11
|
ActiveRecord::Base.connection.execute 'CREATE TABLE parent_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
12
12
|
ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
|
13
|
+
ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER)'
|
13
14
|
ActiveRecord::Base.connection.execute 'CREATE TABLE featureful_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME, name VARCHAR(32))'
|
14
15
|
ActiveRecord::Base.connection.execute 'CREATE TABLE plain_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
15
16
|
ActiveRecord::Base.connection.execute 'CREATE TABLE callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
17
|
+
ActiveRecord::Base.connection.execute 'CREATE TABLE fail_callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
16
18
|
ActiveRecord::Base.connection.execute 'CREATE TABLE related_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER NOT NULL, deleted_at DATETIME)'
|
17
19
|
ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
18
20
|
ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
@@ -100,6 +102,7 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
100
102
|
model.destroy
|
101
103
|
|
102
104
|
assert_equal false, model.deleted_at.nil?
|
105
|
+
assert_equal false, model.really_destroyed?
|
103
106
|
|
104
107
|
assert_equal 0, model.class.count
|
105
108
|
assert_equal 1, model.class.unscoped.count
|
@@ -250,6 +253,20 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
250
253
|
assert_equal 1, ParanoidModel.unscoped.where(id: model.id).count
|
251
254
|
end
|
252
255
|
|
256
|
+
def test_destroy_return_value_on_success
|
257
|
+
model = ParanoidModel.create
|
258
|
+
return_value = model.destroy
|
259
|
+
|
260
|
+
assert_equal(return_value, model)
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_destroy_return_value_on_failure
|
264
|
+
model = FailCallbackModel.create
|
265
|
+
return_value = model.destroy
|
266
|
+
|
267
|
+
assert_equal(return_value, false)
|
268
|
+
end
|
269
|
+
|
253
270
|
def test_restore_behavior_for_callbacks
|
254
271
|
model = CallbackModel.new
|
255
272
|
model.save
|
@@ -265,7 +282,7 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
265
282
|
assert model.instance_variable_get(:@restore_callback_called)
|
266
283
|
end
|
267
284
|
|
268
|
-
def
|
285
|
+
def test_really_destroy
|
269
286
|
model = ParanoidModel.new
|
270
287
|
model.save
|
271
288
|
model.destroy!
|
@@ -273,6 +290,40 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
273
290
|
assert_equal 0, ParanoidModel.unscoped.where(id: model.id).count
|
274
291
|
end
|
275
292
|
|
293
|
+
def test_really_destroyed
|
294
|
+
model = ParanoidModel.new
|
295
|
+
model.save
|
296
|
+
model.destroy!
|
297
|
+
|
298
|
+
assert model.really_destroyed?
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_real_destroy_dependent_destroy
|
302
|
+
parent = ParentModel.create
|
303
|
+
child = parent.very_related_models.create
|
304
|
+
parent.really_destroy!
|
305
|
+
refute RelatedModel.unscoped.exists?(child.id)
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_real_destroy_dependent_destroy_after_normal_destroy
|
309
|
+
parent = ParentModel.create
|
310
|
+
child = parent.very_related_models.create
|
311
|
+
parent.destroy
|
312
|
+
parent.really_destroy!
|
313
|
+
refute RelatedModel.unscoped.exists?(child.id)
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_real_destroy_dependent_destroy_after_normal_destroy_does_not_delete_other_children
|
317
|
+
parent_1 = ParentModel.create
|
318
|
+
child_1 = parent_1.very_related_models.create
|
319
|
+
|
320
|
+
parent_2 = ParentModel.create
|
321
|
+
child_2 = parent_2.very_related_models.create
|
322
|
+
parent_1.destroy
|
323
|
+
parent_1.really_destroy!
|
324
|
+
assert RelatedModel.unscoped.exists?(child_2.id)
|
325
|
+
end
|
326
|
+
|
276
327
|
def test_real_delete
|
277
328
|
model = ParanoidModel.new
|
278
329
|
model.save
|
@@ -335,6 +386,39 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
335
386
|
assert_equal true, second_child.destroyed?
|
336
387
|
end
|
337
388
|
|
389
|
+
# regression tests for #118
|
390
|
+
def test_restore_with_has_one_association
|
391
|
+
# setup and destroy test objects
|
392
|
+
hasOne = ParanoidModelWithHasOne.create
|
393
|
+
belongsTo = ParanoidModelWithBelong.create
|
394
|
+
hasOne.paranoid_model_with_belong = belongsTo
|
395
|
+
hasOne.save!
|
396
|
+
|
397
|
+
hasOne.destroy
|
398
|
+
assert_equal false, hasOne.deleted_at.nil?
|
399
|
+
assert_equal false, belongsTo.deleted_at.nil?
|
400
|
+
|
401
|
+
# Does it restore has_one associations?
|
402
|
+
hasOne.restore(:recursive => true)
|
403
|
+
hasOne.save!
|
404
|
+
|
405
|
+
assert_equal true, hasOne.reload.deleted_at.nil?
|
406
|
+
assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}"
|
407
|
+
assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record"
|
408
|
+
end
|
409
|
+
|
410
|
+
def test_restore_with_nil_has_one_association
|
411
|
+
# setup and destroy test object
|
412
|
+
hasOne = ParanoidModelWithHasOne.create
|
413
|
+
hasOne.destroy
|
414
|
+
assert_equal false, hasOne.reload.deleted_at.nil?
|
415
|
+
|
416
|
+
# Does it raise NoMethodException on restore of nil
|
417
|
+
hasOne.restore(:recursive => true)
|
418
|
+
|
419
|
+
assert hasOne.reload.deleted_at.nil?
|
420
|
+
end
|
421
|
+
|
338
422
|
def test_observers_notified
|
339
423
|
a = ParanoidModelWithObservers.create
|
340
424
|
a.destroy
|
@@ -368,6 +452,13 @@ class ParanoidModel < ActiveRecord::Base
|
|
368
452
|
acts_as_paranoid
|
369
453
|
end
|
370
454
|
|
455
|
+
class FailCallbackModel < ActiveRecord::Base
|
456
|
+
belongs_to :parent_model
|
457
|
+
acts_as_paranoid
|
458
|
+
|
459
|
+
before_destroy { |_| false }
|
460
|
+
end
|
461
|
+
|
371
462
|
class FeaturefulModel < ActiveRecord::Base
|
372
463
|
acts_as_paranoid
|
373
464
|
validates :name, :presence => true, :uniqueness => true
|
@@ -443,3 +534,13 @@ end
|
|
443
534
|
class ParanoidModelWithoutObservers < ParanoidModel
|
444
535
|
self.class.send(remove_method :notify_observers) if method_defined?(:notify_observers)
|
445
536
|
end
|
537
|
+
|
538
|
+
# refer back to regression test for #118
|
539
|
+
class ParanoidModelWithHasOne < ParanoidModel
|
540
|
+
has_one :paranoid_model_with_belong, :dependent => :destroy
|
541
|
+
end
|
542
|
+
|
543
|
+
class ParanoidModelWithBelong < ActiveRecord::Base
|
544
|
+
acts_as_paranoid
|
545
|
+
belongs_to :paranoid_model_with_has_one
|
546
|
+
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: 1.3.
|
4
|
+
version: 1.3.4
|
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: 2015-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '3.
|
26
|
+
version: '3.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- README.md
|
71
71
|
- Rakefile
|
72
72
|
- lib/paranoia.rb
|
73
|
+
- lib/paranoia/rspec.rb
|
73
74
|
- lib/paranoia/version.rb
|
74
75
|
- paranoia.gemspec
|
75
76
|
- test/paranoia_test.rb
|
@@ -92,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
93
|
version: 1.3.6
|
93
94
|
requirements: []
|
94
95
|
rubyforge_project: paranoia
|
95
|
-
rubygems_version: 2.2.
|
96
|
+
rubygems_version: 2.2.2
|
96
97
|
signing_key:
|
97
98
|
specification_version: 4
|
98
99
|
summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much,
|