paranoia 2.1.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -22
- data/lib/paranoia.rb +22 -5
- data/lib/paranoia/version.rb +1 -1
- data/test/paranoia_test.rb +94 -23
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb9d6ab15bd6fb2e445d1cbb7d83d93c920f94f0
|
4
|
+
data.tar.gz: d48bc9001fcdbb023d9312c1706dcba6f602c07d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2609ec5884f55c9d466a69a7d8df51ed380706c54ec47feab1be36666b63c617f4c1abb133e77f2f05552d23df4182170b0d6934938aacadbf9511214a447a39
|
7
|
+
data.tar.gz: 74b632024df0628881ac8ed4d338ac301470ff4a0ce985425055aed32537d0315c2c095b4c8f92ebb5467cc9f750f5ab878e06b1092e71c4582cdd82d17ad7a7
|
data/README.md
CHANGED
@@ -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
|
```
|
@@ -124,6 +124,16 @@ def product
|
|
124
124
|
end
|
125
125
|
```
|
126
126
|
|
127
|
+
If you want to include associated soft-deleted objects, you can (un)scope the association:
|
128
|
+
|
129
|
+
``` ruby
|
130
|
+
class Person < ActiveRecord::Base
|
131
|
+
belongs_to :group, -> { with_deleted }
|
132
|
+
end
|
133
|
+
|
134
|
+
Person.includes(:group).all
|
135
|
+
```
|
136
|
+
|
127
137
|
If you want to find all records, even those which are deleted:
|
128
138
|
|
129
139
|
``` ruby
|
@@ -184,27 +194,6 @@ You can replace the older `acts_as_paranoid` methods as follows:
|
|
184
194
|
The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's
|
185
195
|
`restore` method does not do this.
|
186
196
|
|
187
|
-
## Support for Unique Keys with Null Values
|
188
|
-
|
189
|
-
Most databases ignore null columns when it comes to resolving unique index
|
190
|
-
constraints. This means unique constraints that involve nullable columns may be
|
191
|
-
problematic. Instead of using `NULL` to represent a not-deleted row, you can pick
|
192
|
-
a value that you want paranoia to mean not deleted. Note that you can/should
|
193
|
-
now apply a `NOT NULL` constraint to your `deleted_at` column.
|
194
|
-
|
195
|
-
Per model:
|
196
|
-
|
197
|
-
```ruby
|
198
|
-
# pick some value
|
199
|
-
acts_as_paranoid sentinel_value: DateTime.new(0)
|
200
|
-
```
|
201
|
-
|
202
|
-
or globally in a rails initializer, e.g. `config/initializer/paranoia.rb`
|
203
|
-
|
204
|
-
```ruby
|
205
|
-
Paranoia.default_sentinel_value = DateTime.new(0)
|
206
|
-
```
|
207
|
-
|
208
197
|
## License
|
209
198
|
|
210
199
|
This gem is released under the MIT license.
|
data/lib/paranoia.rb
CHANGED
@@ -33,8 +33,15 @@ module Paranoia
|
|
33
33
|
end
|
34
34
|
alias :deleted :only_deleted
|
35
35
|
|
36
|
-
def restore(
|
37
|
-
Array(
|
36
|
+
def restore(id_or_ids, opts = {})
|
37
|
+
ids = Array(id_or_ids).flatten
|
38
|
+
any_object_instead_of_id = ids.any? { |id| ActiveRecord::Base === id }
|
39
|
+
if any_object_instead_of_id
|
40
|
+
ids.map! { |id| ActiveRecord::Base === id ? id.id : id }
|
41
|
+
ActiveSupport::Deprecation.warn("You are passing an instance of ActiveRecord::Base to `restore`. " \
|
42
|
+
"Please pass the id of the object by calling `.id`")
|
43
|
+
end
|
44
|
+
ids.map { |id| only_deleted.find(id).restore!(opts) }
|
38
45
|
end
|
39
46
|
end
|
40
47
|
|
@@ -59,7 +66,18 @@ module Paranoia
|
|
59
66
|
def destroy
|
60
67
|
transaction do
|
61
68
|
run_callbacks(:destroy) do
|
62
|
-
touch_paranoia_column
|
69
|
+
result = touch_paranoia_column
|
70
|
+
if result && ActiveRecord::VERSION::STRING >= '4.2'
|
71
|
+
each_counter_cached_associations do |association|
|
72
|
+
foreign_key = association.reflection.foreign_key.to_sym
|
73
|
+
unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
|
74
|
+
if send(association.reflection.name)
|
75
|
+
association.decrement_counters
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
result
|
63
81
|
end
|
64
82
|
end
|
65
83
|
end
|
@@ -95,8 +113,7 @@ module Paranoia
|
|
95
113
|
|
96
114
|
# touch paranoia column.
|
97
115
|
# insert time to paranoia column.
|
98
|
-
|
99
|
-
def touch_paranoia_column(with_transaction=false)
|
116
|
+
def touch_paranoia_column
|
100
117
|
raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
101
118
|
if persisted?
|
102
119
|
touch(paranoia_column)
|
data/lib/paranoia/version.rb
CHANGED
data/test/paranoia_test.rb
CHANGED
@@ -12,27 +12,32 @@ end
|
|
12
12
|
|
13
13
|
def setup!
|
14
14
|
connect!
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
15
|
+
{
|
16
|
+
'parent_model_with_counter_cache_columns' => 'related_models_count INTEGER DEFAULT 0',
|
17
|
+
'parent_models' => 'deleted_at DATETIME',
|
18
|
+
'paranoid_models' => 'parent_model_id INTEGER, deleted_at DATETIME',
|
19
|
+
'paranoid_model_with_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER',
|
20
|
+
'paranoid_model_with_build_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_and_build_id INTEGER, name VARCHAR(32)',
|
21
|
+
'paranoid_model_with_anthor_class_name_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER',
|
22
|
+
'paranoid_model_with_foreign_key_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER',
|
23
|
+
'not_paranoid_model_with_belongs' => 'parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER',
|
24
|
+
'paranoid_model_with_has_one_and_builds' => 'parent_model_id INTEGER, color VARCHAR(32), deleted_at DATETIME, has_one_foreign_key_id INTEGER',
|
25
|
+
'featureful_models' => 'deleted_at DATETIME, name VARCHAR(32)',
|
26
|
+
'plain_models' => 'deleted_at DATETIME',
|
27
|
+
'callback_models' => 'deleted_at DATETIME',
|
28
|
+
'fail_callback_models' => 'deleted_at DATETIME',
|
29
|
+
'related_models' => 'parent_model_id INTEGER, parent_model_with_counter_cache_column_id INTEGER, deleted_at DATETIME',
|
30
|
+
'asplode_models' => 'parent_model_id INTEGER, deleted_at DATETIME',
|
31
|
+
'employers' => 'deleted_at DATETIME',
|
32
|
+
'employees' => 'deleted_at DATETIME',
|
33
|
+
'jobs' => 'employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME',
|
34
|
+
'custom_column_models' => 'destroyed_at DATETIME',
|
35
|
+
'custom_sentinel_models' => 'deleted_at DATETIME NOT NULL',
|
36
|
+
'non_paranoid_models' => 'parent_model_id INTEGER',
|
37
|
+
'polymorphic_models' => 'parent_id INTEGER, parent_type STRING, deleted_at DATETIME'
|
38
|
+
}.each do |table_name, columns_as_sql_string|
|
39
|
+
ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
|
40
|
+
end
|
36
41
|
end
|
37
42
|
|
38
43
|
class WithDifferentConnection < ActiveRecord::Base
|
@@ -758,6 +763,56 @@ class ParanoiaTest < test_framework
|
|
758
763
|
assert_equal 0, polymorphic.class.count
|
759
764
|
end
|
760
765
|
|
766
|
+
def test_counter_cache_column_update_on_destroy#_and_restore_and_really_destroy
|
767
|
+
parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
|
768
|
+
related_model = parent_model_with_counter_cache_column.related_models.create
|
769
|
+
|
770
|
+
assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
|
771
|
+
related_model.destroy
|
772
|
+
assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
|
773
|
+
end
|
774
|
+
|
775
|
+
def test_callbacks_for_counter_cache_column_update_on_destroy
|
776
|
+
parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
|
777
|
+
related_model = parent_model_with_counter_cache_column.related_models.create
|
778
|
+
|
779
|
+
assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
|
780
|
+
assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
|
781
|
+
|
782
|
+
related_model.destroy
|
783
|
+
|
784
|
+
assert related_model.instance_variable_get(:@after_destroy_callback_called)
|
785
|
+
# assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
|
786
|
+
end
|
787
|
+
|
788
|
+
# TODO: find a fix for Rails 4.1
|
789
|
+
if ActiveRecord::VERSION::STRING !~ /\A4\.1/
|
790
|
+
def test_counter_cache_column_update_on_really_destroy
|
791
|
+
parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
|
792
|
+
related_model = parent_model_with_counter_cache_column.related_models.create
|
793
|
+
|
794
|
+
assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
|
795
|
+
related_model.really_destroy!
|
796
|
+
assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
# TODO: find a fix for Rails 4.0 and 4.1
|
801
|
+
if ActiveRecord::VERSION::STRING >= '4.2'
|
802
|
+
def test_callbacks_for_counter_cache_column_update_on_really_destroy!
|
803
|
+
parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
|
804
|
+
related_model = parent_model_with_counter_cache_column.related_models.create
|
805
|
+
|
806
|
+
assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
|
807
|
+
assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
|
808
|
+
|
809
|
+
related_model.really_destroy!
|
810
|
+
|
811
|
+
assert related_model.instance_variable_get(:@after_destroy_callback_called)
|
812
|
+
assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
761
816
|
private
|
762
817
|
def get_featureful_model
|
763
818
|
FeaturefulModel.new(:name => "not empty")
|
@@ -814,9 +869,27 @@ class ParentModel < ActiveRecord::Base
|
|
814
869
|
has_one :polymorphic_model, as: :parent, dependent: :destroy
|
815
870
|
end
|
816
871
|
|
872
|
+
class ParentModelWithCounterCacheColumn < ActiveRecord::Base
|
873
|
+
has_many :related_models
|
874
|
+
end
|
875
|
+
|
817
876
|
class RelatedModel < ActiveRecord::Base
|
818
877
|
acts_as_paranoid
|
819
878
|
belongs_to :parent_model
|
879
|
+
belongs_to :parent_model_with_counter_cache_column, counter_cache: true
|
880
|
+
|
881
|
+
after_destroy do |model|
|
882
|
+
if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0
|
883
|
+
model.instance_variable_set :@after_destroy_callback_called, true
|
884
|
+
end
|
885
|
+
end
|
886
|
+
after_commit :set_after_commit_on_destroy_callback_called, on: :destroy
|
887
|
+
|
888
|
+
def set_after_commit_on_destroy_callback_called
|
889
|
+
if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0
|
890
|
+
self.instance_variable_set :@after_commit_on_destroy_callback_called, true
|
891
|
+
end
|
892
|
+
end
|
820
893
|
end
|
821
894
|
|
822
895
|
class Employer < ActiveRecord::Base
|
@@ -914,8 +987,6 @@ class FlaggedModelWithCustomIndex < PlainModel
|
|
914
987
|
acts_as_paranoid :flag_column => :is_deleted, :indexed_column => :is_deleted
|
915
988
|
end
|
916
989
|
|
917
|
-
|
918
|
-
|
919
990
|
class AsplodeModel < ActiveRecord::Base
|
920
991
|
acts_as_paranoid
|
921
992
|
before_destroy do |r|
|
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.1.
|
4
|
+
version: 2.1.1
|
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: 2015-
|
11
|
+
date: 2015-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
94
|
version: 1.3.6
|
95
95
|
requirements: []
|
96
96
|
rubyforge_project: paranoia
|
97
|
-
rubygems_version: 2.
|
97
|
+
rubygems_version: 2.4.6
|
98
98
|
signing_key:
|
99
99
|
specification_version: 4
|
100
100
|
summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much,
|