paranoia 2.1.0 → 2.1.1
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 +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,
|