acts_as_paranoid 0.6.0 → 0.7.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/CHANGELOG.md +128 -0
- data/README.md +154 -56
- data/lib/acts_as_paranoid.rb +34 -31
- data/lib/acts_as_paranoid/associations.rb +21 -17
- data/lib/acts_as_paranoid/core.rb +139 -58
- data/lib/acts_as_paranoid/relation.rb +2 -0
- data/lib/acts_as_paranoid/validations.rb +8 -69
- data/lib/acts_as_paranoid/version.rb +3 -1
- data/test/test_associations.rb +157 -38
- data/test/test_core.rb +269 -48
- data/test/test_default_scopes.rb +7 -6
- data/test/test_helper.rb +155 -62
- data/test/test_inheritance.rb +3 -1
- data/test/test_relations.rb +18 -10
- data/test/test_validations.rb +9 -7
- metadata +92 -33
- data/lib/acts_as_paranoid/preloader_association.rb +0 -16
- data/test/test_preloader_association.rb +0 -27
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/array/wrap"
|
2
4
|
|
3
5
|
module ActsAsParanoid
|
4
6
|
module Validations
|
@@ -6,80 +8,17 @@ module ActsAsParanoid
|
|
6
8
|
base.extend ClassMethods
|
7
9
|
end
|
8
10
|
|
9
|
-
class UniquenessWithoutDeletedValidator
|
10
|
-
|
11
|
-
version = version.to_s
|
12
|
-
name = "V#{version.tr('.', '_')}"
|
13
|
-
unless constants.include? name.to_sym
|
14
|
-
raise "Unknown validator version #{version.inspect}; expected one of #{constants.sort.join(', ')}"
|
15
|
-
end
|
16
|
-
const_get name
|
17
|
-
end
|
18
|
-
|
19
|
-
class V5 < ActiveRecord::Validations::UniquenessValidator
|
20
|
-
def validate_each(record, attribute, value)
|
21
|
-
finder_class = find_finder_class_for(record)
|
22
|
-
table = finder_class.arel_table
|
23
|
-
|
24
|
-
relation = build_relation(finder_class, attribute, value)
|
25
|
-
[Array(finder_class.primary_key), Array(record.send(:id))].transpose.each do |pk_key, pk_value|
|
26
|
-
relation = relation.where(table[pk_key.to_sym].not_eq(pk_value))
|
27
|
-
end if record.persisted?
|
28
|
-
|
29
|
-
Array.wrap(options[:scope]).each do |scope_item|
|
30
|
-
relation = relation.where(table[scope_item].eq(record.public_send(scope_item)))
|
31
|
-
end
|
32
|
-
|
33
|
-
if relation.where(finder_class.paranoid_default_scope).exists?(relation)
|
34
|
-
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
protected
|
39
|
-
|
40
|
-
def build_relation(klass, attribute, value)
|
41
|
-
return super(klass, klass.arel_table, attribute, value) if ActiveRecord::VERSION::MINOR == 0
|
42
|
-
super
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class V4 < ActiveRecord::Validations::UniquenessValidator
|
47
|
-
def validate_each(record, attribute, value)
|
48
|
-
finder_class = find_finder_class_for(record)
|
49
|
-
table = finder_class.arel_table
|
50
|
-
|
51
|
-
# TODO: Use record.class.column_types[attribute.to_s].coder ?
|
52
|
-
coder = record.class.column_types[attribute.to_s]
|
53
|
-
|
54
|
-
if value && coder
|
55
|
-
value = if coder.respond_to? :type_cast_for_database
|
56
|
-
coder.type_cast_for_database value
|
57
|
-
else
|
58
|
-
coder.type_cast_for_write value
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
relation = build_relation(finder_class, table, attribute, value)
|
63
|
-
[Array(finder_class.primary_key), Array(record.send(:id))].transpose.each do |pk_key, pk_value|
|
64
|
-
relation = relation.and(table[pk_key.to_sym].not_eq(pk_value))
|
65
|
-
end if record.persisted?
|
66
|
-
|
67
|
-
Array.wrap(options[:scope]).each do |scope_item|
|
68
|
-
scope_value = record.send(scope_item)
|
69
|
-
relation = relation.and(table[scope_item].eq(scope_value))
|
70
|
-
end
|
11
|
+
class UniquenessWithoutDeletedValidator < ActiveRecord::Validations::UniquenessValidator
|
12
|
+
private
|
71
13
|
|
72
|
-
|
73
|
-
|
74
|
-
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
75
|
-
end
|
76
|
-
end
|
14
|
+
def build_relation(klass, attribute, value)
|
15
|
+
super.where(klass.paranoid_default_scope)
|
77
16
|
end
|
78
17
|
end
|
79
18
|
|
80
19
|
module ClassMethods
|
81
20
|
def validates_uniqueness_of_without_deleted(*attr_names)
|
82
|
-
validates_with UniquenessWithoutDeletedValidator
|
21
|
+
validates_with UniquenessWithoutDeletedValidator, _merge_attributes(attr_names)
|
83
22
|
end
|
84
23
|
end
|
85
24
|
end
|
data/test/test_associations.rb
CHANGED
@@ -1,27 +1,34 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
2
4
|
|
3
5
|
class AssociationsTest < ParanoidBaseTest
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
paranoid_company_1.paranoid_products.create! :name => "ParanoidProduct #1"
|
8
|
-
paranoid_company_2.paranoid_products.create! :name => "ParanoidProduct #2"
|
6
|
+
def test_removal_with_destroy_associations
|
7
|
+
paranoid_company = ParanoidDestroyCompany.create! name: "ParanoidDestroyCompany #1"
|
8
|
+
paranoid_company.paranoid_products.create! name: "ParanoidProduct #1"
|
9
9
|
|
10
10
|
assert_equal 1, ParanoidDestroyCompany.count
|
11
|
-
assert_equal 1,
|
12
|
-
assert_equal 2, ParanoidProduct.count
|
11
|
+
assert_equal 1, ParanoidProduct.count
|
13
12
|
|
14
13
|
ParanoidDestroyCompany.first.destroy
|
15
14
|
assert_equal 0, ParanoidDestroyCompany.count
|
16
|
-
assert_equal
|
15
|
+
assert_equal 0, ParanoidProduct.count
|
17
16
|
assert_equal 1, ParanoidDestroyCompany.with_deleted.count
|
18
|
-
assert_equal
|
17
|
+
assert_equal 1, ParanoidProduct.with_deleted.count
|
19
18
|
|
20
19
|
ParanoidDestroyCompany.with_deleted.first.destroy
|
21
20
|
assert_equal 0, ParanoidDestroyCompany.count
|
22
|
-
assert_equal
|
21
|
+
assert_equal 0, ParanoidProduct.count
|
23
22
|
assert_equal 0, ParanoidDestroyCompany.with_deleted.count
|
24
|
-
assert_equal
|
23
|
+
assert_equal 0, ParanoidProduct.with_deleted.count
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_removal_with_delete_all_associations
|
27
|
+
paranoid_company = ParanoidDeleteCompany.create! name: "ParanoidDestroyCompany #1"
|
28
|
+
paranoid_company.paranoid_products.create! name: "ParanoidProduct #2"
|
29
|
+
|
30
|
+
assert_equal 1, ParanoidDeleteCompany.count
|
31
|
+
assert_equal 1, ParanoidProduct.count
|
25
32
|
|
26
33
|
ParanoidDeleteCompany.first.destroy
|
27
34
|
assert_equal 0, ParanoidDeleteCompany.count
|
@@ -38,40 +45,94 @@ class AssociationsTest < ParanoidBaseTest
|
|
38
45
|
|
39
46
|
def test_belongs_to_with_scope_option
|
40
47
|
paranoid_has_many_dependant = ParanoidHasManyDependant.new
|
48
|
+
|
49
|
+
expected_includes_values = ParanoidTime.includes(:not_paranoid).includes_values
|
50
|
+
includes_values = paranoid_has_many_dependant
|
51
|
+
.association(:paranoid_time_with_scope).scope.includes_values
|
52
|
+
|
53
|
+
assert_equal expected_includes_values, includes_values
|
54
|
+
|
55
|
+
paranoid_time = ParanoidTime.create(name: "not-hello")
|
56
|
+
paranoid_has_many_dependant.paranoid_time = paranoid_time
|
57
|
+
paranoid_has_many_dependant.save!
|
58
|
+
|
59
|
+
assert_nil paranoid_has_many_dependant.paranoid_time_with_scope
|
60
|
+
|
61
|
+
paranoid_time.update(name: "hello")
|
62
|
+
|
63
|
+
paranoid_has_many_dependant.reload
|
64
|
+
|
65
|
+
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_with_scope
|
66
|
+
|
67
|
+
paranoid_time.destroy
|
68
|
+
|
69
|
+
paranoid_has_many_dependant.reload
|
70
|
+
|
71
|
+
assert_nil paranoid_has_many_dependant.paranoid_time_with_scope
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_belongs_to_with_scope_and_deleted_option
|
75
|
+
paranoid_has_many_dependant = ParanoidHasManyDependant.new
|
41
76
|
includes_values = ParanoidTime.includes(:not_paranoid).includes_values
|
42
77
|
|
43
|
-
assert_equal includes_values, paranoid_has_many_dependant
|
78
|
+
assert_equal includes_values, paranoid_has_many_dependant
|
79
|
+
.association(:paranoid_time_with_scope_with_deleted).scope.includes_values
|
80
|
+
|
81
|
+
paranoid_time = ParanoidTime.create(name: "not-hello")
|
82
|
+
paranoid_has_many_dependant.paranoid_time = paranoid_time
|
83
|
+
paranoid_has_many_dependant.save!
|
84
|
+
|
85
|
+
assert_nil paranoid_has_many_dependant.paranoid_time_with_scope_with_deleted
|
86
|
+
|
87
|
+
paranoid_time.update(name: "hello")
|
88
|
+
paranoid_has_many_dependant.reload
|
89
|
+
|
90
|
+
assert_equal paranoid_time, paranoid_has_many_dependant
|
91
|
+
.paranoid_time_with_scope_with_deleted
|
92
|
+
|
93
|
+
paranoid_time.destroy
|
94
|
+
paranoid_has_many_dependant.reload
|
95
|
+
|
96
|
+
assert_equal paranoid_time, paranoid_has_many_dependant
|
97
|
+
.paranoid_time_with_scope_with_deleted
|
44
98
|
end
|
45
99
|
|
46
100
|
def test_belongs_to_with_deleted
|
47
101
|
paranoid_time = ParanoidTime.first
|
48
|
-
paranoid_has_many_dependant = paranoid_time.paranoid_has_many_dependants
|
102
|
+
paranoid_has_many_dependant = paranoid_time.paranoid_has_many_dependants
|
103
|
+
.create(name: "dependant!")
|
49
104
|
|
50
105
|
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time
|
51
106
|
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_with_deleted
|
52
107
|
|
53
108
|
paranoid_time.destroy
|
109
|
+
paranoid_has_many_dependant.reload
|
54
110
|
|
55
|
-
assert_nil paranoid_has_many_dependant.
|
56
|
-
assert_equal paranoid_time, paranoid_has_many_dependant.
|
111
|
+
assert_nil paranoid_has_many_dependant.paranoid_time
|
112
|
+
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_with_deleted
|
57
113
|
end
|
58
114
|
|
59
115
|
def test_belongs_to_polymorphic_with_deleted
|
60
116
|
paranoid_time = ParanoidTime.first
|
61
|
-
paranoid_has_many_dependant = ParanoidHasManyDependant
|
117
|
+
paranoid_has_many_dependant = ParanoidHasManyDependant
|
118
|
+
.create!(name: "dependant!", paranoid_time_polymorphic_with_deleted: paranoid_time)
|
62
119
|
|
63
120
|
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time
|
64
|
-
assert_equal paranoid_time, paranoid_has_many_dependant
|
121
|
+
assert_equal paranoid_time, paranoid_has_many_dependant
|
122
|
+
.paranoid_time_polymorphic_with_deleted
|
65
123
|
|
66
124
|
paranoid_time.destroy
|
67
125
|
|
68
126
|
assert_nil paranoid_has_many_dependant.reload.paranoid_time
|
69
|
-
assert_equal paranoid_time, paranoid_has_many_dependant
|
127
|
+
assert_equal paranoid_time, paranoid_has_many_dependant
|
128
|
+
.reload.paranoid_time_polymorphic_with_deleted
|
70
129
|
end
|
71
130
|
|
72
131
|
def test_belongs_to_nil_polymorphic_with_deleted
|
73
132
|
paranoid_time = ParanoidTime.first
|
74
|
-
paranoid_has_many_dependant =
|
133
|
+
paranoid_has_many_dependant =
|
134
|
+
ParanoidHasManyDependant.create!(name: "dependant!",
|
135
|
+
paranoid_time_polymorphic_with_deleted: nil)
|
75
136
|
|
76
137
|
assert_nil paranoid_has_many_dependant.paranoid_time
|
77
138
|
assert_nil paranoid_has_many_dependant.paranoid_time_polymorphic_with_deleted
|
@@ -83,19 +144,23 @@ class AssociationsTest < ParanoidBaseTest
|
|
83
144
|
end
|
84
145
|
|
85
146
|
def test_belongs_to_options
|
86
|
-
paranoid_time = ParanoidHasManyDependant.reflections
|
147
|
+
paranoid_time = ParanoidHasManyDependant.reflections
|
148
|
+
.with_indifferent_access[:paranoid_time]
|
87
149
|
assert_equal :belongs_to, paranoid_time.macro
|
88
150
|
assert_nil paranoid_time.options[:with_deleted]
|
89
151
|
end
|
90
152
|
|
91
153
|
def test_belongs_to_with_deleted_options
|
92
|
-
paranoid_time_with_deleted =
|
154
|
+
paranoid_time_with_deleted =
|
155
|
+
ParanoidHasManyDependant.reflections
|
156
|
+
.with_indifferent_access[:paranoid_time_with_deleted]
|
93
157
|
assert_equal :belongs_to, paranoid_time_with_deleted.macro
|
94
158
|
assert paranoid_time_with_deleted.options[:with_deleted]
|
95
159
|
end
|
96
160
|
|
97
161
|
def test_belongs_to_polymorphic_with_deleted_options
|
98
|
-
paranoid_time_polymorphic_with_deleted = ParanoidHasManyDependant.reflections
|
162
|
+
paranoid_time_polymorphic_with_deleted = ParanoidHasManyDependant.reflections
|
163
|
+
.with_indifferent_access[:paranoid_time_polymorphic_with_deleted]
|
99
164
|
assert_equal :belongs_to, paranoid_time_polymorphic_with_deleted.macro
|
100
165
|
assert paranoid_time_polymorphic_with_deleted.options[:with_deleted]
|
101
166
|
end
|
@@ -118,6 +183,50 @@ class AssociationsTest < ParanoidBaseTest
|
|
118
183
|
assert_equal [child], parent.paranoid_has_many_dependants.with_deleted.to_a
|
119
184
|
end
|
120
185
|
|
186
|
+
def test_join_with_model_with_deleted
|
187
|
+
obj = ParanoidHasManyDependant.create(paranoid_time: ParanoidTime.create)
|
188
|
+
assert_not_nil obj.paranoid_time
|
189
|
+
assert_not_nil obj.paranoid_time_with_deleted
|
190
|
+
|
191
|
+
obj.paranoid_time.destroy
|
192
|
+
obj.reload
|
193
|
+
|
194
|
+
assert_nil obj.paranoid_time
|
195
|
+
assert_not_nil obj.paranoid_time_with_deleted
|
196
|
+
|
197
|
+
# Note that obj is destroyed because of dependent: :destroy in ParanoidTime
|
198
|
+
assert obj.destroyed?
|
199
|
+
|
200
|
+
assert_empty ParanoidHasManyDependant.with_deleted.joins(:paranoid_time)
|
201
|
+
assert_equal [obj],
|
202
|
+
ParanoidHasManyDependant.with_deleted.joins(:paranoid_time_with_deleted)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_includes_with_deleted
|
206
|
+
paranoid_time = ParanoidTime.first
|
207
|
+
paranoid_time.paranoid_has_many_dependants.create(name: "dependant!")
|
208
|
+
|
209
|
+
paranoid_time.destroy
|
210
|
+
|
211
|
+
ParanoidHasManyDependant.with_deleted
|
212
|
+
.includes(:paranoid_time_with_deleted).each do |hasmany|
|
213
|
+
assert_not_nil hasmany.paranoid_time_with_deleted
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_includes_with_deleted_with_polymorphic_parent
|
218
|
+
not_paranoid_parent = NotParanoidHasManyAsParent.create(name: "not paranoid parent")
|
219
|
+
paranoid_parent = ParanoidHasManyAsParent.create(name: "paranoid parent")
|
220
|
+
ParanoidBelongsToPolymorphic.create(name: "belongs_to", parent: not_paranoid_parent)
|
221
|
+
ParanoidBelongsToPolymorphic.create(name: "belongs_to", parent: paranoid_parent)
|
222
|
+
|
223
|
+
paranoid_parent.destroy
|
224
|
+
|
225
|
+
ParanoidBelongsToPolymorphic.with_deleted.includes(:parent).each do |hasmany|
|
226
|
+
assert_not_nil hasmany.parent
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
121
230
|
def test_cannot_find_a_paranoid_deleted_many_many_association
|
122
231
|
left = ParanoidManyManyParentLeft.create
|
123
232
|
right = ParanoidManyManyParentRight.create
|
@@ -128,8 +237,10 @@ class AssociationsTest < ParanoidBaseTest
|
|
128
237
|
left.reload
|
129
238
|
|
130
239
|
assert_equal [], left.paranoid_many_many_children, "Linking objects not deleted"
|
131
|
-
assert_equal [], left.paranoid_many_many_parent_rights,
|
132
|
-
|
240
|
+
assert_equal [], left.paranoid_many_many_parent_rights,
|
241
|
+
"Associated objects not unlinked"
|
242
|
+
assert_equal right, ParanoidManyManyParentRight.find(right.id),
|
243
|
+
"Associated object deleted"
|
133
244
|
end
|
134
245
|
|
135
246
|
def test_cannot_find_a_paranoid_destroyed_many_many_association
|
@@ -142,11 +253,13 @@ class AssociationsTest < ParanoidBaseTest
|
|
142
253
|
left.reload
|
143
254
|
|
144
255
|
assert_equal [], left.paranoid_many_many_children, "Linking objects not deleted"
|
145
|
-
assert_equal [], left.paranoid_many_many_parent_rights,
|
146
|
-
|
256
|
+
assert_equal [], left.paranoid_many_many_parent_rights,
|
257
|
+
"Associated objects not unlinked"
|
258
|
+
assert_equal right, ParanoidManyManyParentRight.find(right.id),
|
259
|
+
"Associated object deleted"
|
147
260
|
end
|
148
261
|
|
149
|
-
def
|
262
|
+
def test_cannot_find_a_has_many_through_object_when_its_linking_object_is_soft_destroyed
|
150
263
|
left = ParanoidManyManyParentLeft.create
|
151
264
|
right = ParanoidManyManyParentRight.create
|
152
265
|
left.paranoid_many_many_parent_rights << right
|
@@ -175,8 +288,10 @@ class AssociationsTest < ParanoidBaseTest
|
|
175
288
|
left.paranoid_many_many_parent_rights << right
|
176
289
|
|
177
290
|
child = left.paranoid_many_many_children.first
|
178
|
-
assert_equal left, child.paranoid_many_many_parent_left,
|
179
|
-
|
291
|
+
assert_equal left, child.paranoid_many_many_parent_left,
|
292
|
+
"Child's left parent is incorrect"
|
293
|
+
assert_equal right, child.paranoid_many_many_parent_right,
|
294
|
+
"Child's right parent is incorrect"
|
180
295
|
|
181
296
|
left.paranoid_many_many_parent_rights.clear
|
182
297
|
|
@@ -189,8 +304,10 @@ class AssociationsTest < ParanoidBaseTest
|
|
189
304
|
left.paranoid_many_many_parent_rights << right
|
190
305
|
|
191
306
|
child = left.paranoid_many_many_children.first
|
192
|
-
assert_equal left, child.paranoid_many_many_parent_left,
|
193
|
-
|
307
|
+
assert_equal left, child.paranoid_many_many_parent_left,
|
308
|
+
"Child's left parent is incorrect"
|
309
|
+
assert_equal right, child.paranoid_many_many_parent_right,
|
310
|
+
"Child's right parent is incorrect"
|
194
311
|
|
195
312
|
left.paranoid_many_many_parent_rights.destroy(right)
|
196
313
|
|
@@ -203,8 +320,10 @@ class AssociationsTest < ParanoidBaseTest
|
|
203
320
|
left.paranoid_many_many_parent_rights << right
|
204
321
|
|
205
322
|
child = left.paranoid_many_many_children.first
|
206
|
-
assert_equal left, child.paranoid_many_many_parent_left,
|
207
|
-
|
323
|
+
assert_equal left, child.paranoid_many_many_parent_left,
|
324
|
+
"Child's left parent is incorrect"
|
325
|
+
assert_equal right, child.paranoid_many_many_parent_right,
|
326
|
+
"Child's right parent is incorrect"
|
208
327
|
|
209
328
|
left.paranoid_many_many_parent_rights.delete(right)
|
210
329
|
|
@@ -228,12 +347,12 @@ class AssociationsTest < ParanoidBaseTest
|
|
228
347
|
end
|
229
348
|
|
230
349
|
def test_mass_assignment_of_paranoid_column_enabled
|
231
|
-
if
|
232
|
-
skip
|
350
|
+
if Gem.loaded_specs["activerecord"].version >= Gem::Version.new("5.2.0")
|
351
|
+
skip "Creation as deleted is not supported with Rails >= 5.2"
|
233
352
|
end
|
234
353
|
now = Time.now
|
235
|
-
record = ParanoidTime.create! :
|
236
|
-
assert_equal
|
354
|
+
record = ParanoidTime.create! name: "Foo", deleted_at: now
|
355
|
+
assert_equal "Foo", record.name
|
237
356
|
assert_equal now, record.deleted_at
|
238
357
|
end
|
239
358
|
end
|
data/test/test_core.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
2
4
|
|
3
5
|
class ParanoidTest < ParanoidBaseTest
|
4
6
|
def test_paranoid?
|
@@ -69,6 +71,13 @@ class ParanoidTest < ParanoidBaseTest
|
|
69
71
|
assert_not_nil pt.paranoid_value
|
70
72
|
end
|
71
73
|
|
74
|
+
def test_non_persisted_delete
|
75
|
+
pt = ParanoidTime.new
|
76
|
+
assert_nil pt.paranoid_value
|
77
|
+
pt.delete
|
78
|
+
assert_not_nil pt.paranoid_value
|
79
|
+
end
|
80
|
+
|
72
81
|
def test_non_persisted_destroy!
|
73
82
|
pt = ParanoidTime.new
|
74
83
|
assert_nil pt.paranoid_value
|
@@ -94,12 +103,34 @@ class ParanoidTest < ParanoidBaseTest
|
|
94
103
|
assert_equal 1, ParanoidString.count
|
95
104
|
end
|
96
105
|
|
106
|
+
def test_recovery!
|
107
|
+
ParanoidBoolean.first.destroy
|
108
|
+
ParanoidBoolean.create(name: "paranoid")
|
109
|
+
|
110
|
+
assert_raise do
|
111
|
+
ParanoidBoolean.only_deleted.first.recover!
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Rails does not allow saving deleted records
|
116
|
+
def test_no_save_after_destroy
|
117
|
+
paranoid = ParanoidString.first
|
118
|
+
paranoid.destroy
|
119
|
+
paranoid.name = "Let's update!"
|
120
|
+
|
121
|
+
assert_not paranoid.save
|
122
|
+
assert_raises ActiveRecord::RecordNotSaved do
|
123
|
+
paranoid.save!
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
97
127
|
def setup_recursive_tests
|
98
128
|
@paranoid_time_object = ParanoidTime.first
|
99
129
|
|
100
130
|
# Create one extra ParanoidHasManyDependant record so that we can validate
|
101
131
|
# the correct dependants are recovered.
|
102
|
-
ParanoidTime.where(
|
132
|
+
ParanoidTime.where("id <> ?", @paranoid_time_object.id).first
|
133
|
+
.paranoid_has_many_dependants.create(name: "should not be recovered").destroy
|
103
134
|
|
104
135
|
@paranoid_boolean_count = ParanoidBoolean.count
|
105
136
|
|
@@ -108,20 +139,21 @@ class ParanoidTest < ParanoidBaseTest
|
|
108
139
|
assert_equal 1, NotParanoid.count
|
109
140
|
|
110
141
|
(1..3).each do |i|
|
111
|
-
has_many_object = @paranoid_time_object.paranoid_has_many_dependants
|
112
|
-
|
142
|
+
has_many_object = @paranoid_time_object.paranoid_has_many_dependants
|
143
|
+
.create(name: "has_many_#{i}")
|
144
|
+
has_many_object.create_paranoid_belongs_dependant(name: "belongs_to_#{i}")
|
113
145
|
has_many_object.save
|
114
146
|
|
115
|
-
paranoid_boolean = @paranoid_time_object.paranoid_booleans
|
116
|
-
|
147
|
+
paranoid_boolean = @paranoid_time_object.paranoid_booleans
|
148
|
+
.create(name: "boolean_#{i}")
|
149
|
+
paranoid_boolean.create_paranoid_has_one_dependant(name: "has_one_#{i}")
|
117
150
|
paranoid_boolean.save
|
118
151
|
|
119
|
-
@paranoid_time_object.not_paranoids.create(:
|
120
|
-
|
152
|
+
@paranoid_time_object.not_paranoids.create(name: "not_paranoid_a#{i}")
|
121
153
|
end
|
122
154
|
|
123
|
-
@paranoid_time_object.create_not_paranoid(:
|
124
|
-
@paranoid_time_object.create_has_one_not_paranoid(:
|
155
|
+
@paranoid_time_object.create_not_paranoid(name: "not_paranoid_belongs_to")
|
156
|
+
@paranoid_time_object.create_has_one_not_paranoid(name: "has_one_not_paranoid")
|
125
157
|
|
126
158
|
assert_equal 3, ParanoidTime.count
|
127
159
|
assert_equal 3, ParanoidHasManyDependant.count
|
@@ -172,7 +204,7 @@ class ParanoidTest < ParanoidBaseTest
|
|
172
204
|
@paranoid_time_object.destroy
|
173
205
|
@paranoid_time_object.reload
|
174
206
|
|
175
|
-
@paranoid_time_object.recover(:
|
207
|
+
@paranoid_time_object.recover(recursive: true)
|
176
208
|
|
177
209
|
assert_equal 3, ParanoidTime.count
|
178
210
|
assert_equal 3, ParanoidHasManyDependant.count
|
@@ -193,14 +225,14 @@ class ParanoidTest < ParanoidBaseTest
|
|
193
225
|
@paranoid_time_object.paranoid_has_many_dependants.first.destroy
|
194
226
|
end
|
195
227
|
Time.stub :now, 1.hour.ago do
|
196
|
-
@paranoid_time_object.paranoid_has_many_dependants
|
197
|
-
last.paranoid_belongs_dependant
|
198
|
-
destroy
|
228
|
+
@paranoid_time_object.paranoid_has_many_dependants
|
229
|
+
.last.paranoid_belongs_dependant
|
230
|
+
.destroy
|
199
231
|
end
|
200
232
|
@paranoid_time_object.destroy
|
201
233
|
@paranoid_time_object.reload
|
202
234
|
|
203
|
-
@paranoid_time_object.recover(:
|
235
|
+
@paranoid_time_object.recover(recursive: true)
|
204
236
|
|
205
237
|
assert_equal 3, ParanoidTime.count
|
206
238
|
assert_equal 2, ParanoidHasManyDependant.count
|
@@ -213,17 +245,17 @@ class ParanoidTest < ParanoidBaseTest
|
|
213
245
|
|
214
246
|
def test_recursive_recovery_for_belongs_to_polymorphic
|
215
247
|
child_1 = ParanoidAndroid.create
|
216
|
-
section_1 = ParanoidSection.create(:
|
248
|
+
section_1 = ParanoidSection.create(paranoid_thing: child_1)
|
217
249
|
|
218
|
-
child_2 = ParanoidPolygon.create(:
|
219
|
-
section_2 = ParanoidSection.create(:
|
250
|
+
child_2 = ParanoidPolygon.create(sides: 3)
|
251
|
+
section_2 = ParanoidSection.create(paranoid_thing: child_2)
|
220
252
|
|
221
253
|
assert_equal section_1.paranoid_thing, child_1
|
222
254
|
assert_equal section_1.paranoid_thing.class, ParanoidAndroid
|
223
255
|
assert_equal section_2.paranoid_thing, child_2
|
224
256
|
assert_equal section_2.paranoid_thing.class, ParanoidPolygon
|
225
257
|
|
226
|
-
parent = ParanoidTime.create(:
|
258
|
+
parent = ParanoidTime.create(name: "paranoid_parent")
|
227
259
|
parent.paranoid_sections << section_1
|
228
260
|
parent.paranoid_sections << section_2
|
229
261
|
|
@@ -254,7 +286,7 @@ class ParanoidTest < ParanoidBaseTest
|
|
254
286
|
@paranoid_time_object.destroy
|
255
287
|
@paranoid_time_object.reload
|
256
288
|
|
257
|
-
@paranoid_time_object.recover(:
|
289
|
+
@paranoid_time_object.recover(recursive: false)
|
258
290
|
|
259
291
|
assert_equal 3, ParanoidTime.count
|
260
292
|
assert_equal 0, ParanoidHasManyDependant.count
|
@@ -265,6 +297,24 @@ class ParanoidTest < ParanoidBaseTest
|
|
265
297
|
assert_equal 0, HasOneNotParanoid.count
|
266
298
|
end
|
267
299
|
|
300
|
+
def test_dirty
|
301
|
+
pt = ParanoidTime.create
|
302
|
+
pt.destroy
|
303
|
+
assert_not pt.changed?
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_delete_dirty
|
307
|
+
pt = ParanoidTime.create
|
308
|
+
pt.delete
|
309
|
+
assert_not pt.changed?
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_destroy_fully_dirty
|
313
|
+
pt = ParanoidTime.create
|
314
|
+
pt.destroy_fully!
|
315
|
+
assert_not pt.changed?
|
316
|
+
end
|
317
|
+
|
268
318
|
def test_deleted?
|
269
319
|
ParanoidTime.first.destroy
|
270
320
|
assert ParanoidTime.with_deleted.first.deleted?
|
@@ -273,6 +323,43 @@ class ParanoidTest < ParanoidBaseTest
|
|
273
323
|
assert ParanoidString.with_deleted.first.deleted?
|
274
324
|
end
|
275
325
|
|
326
|
+
def test_delete_deleted?
|
327
|
+
ParanoidTime.first.delete
|
328
|
+
assert ParanoidTime.with_deleted.first.deleted?
|
329
|
+
|
330
|
+
ParanoidString.first.delete
|
331
|
+
assert ParanoidString.with_deleted.first.deleted?
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_destroy_fully_deleted?
|
335
|
+
object = ParanoidTime.first
|
336
|
+
object.destroy_fully!
|
337
|
+
assert object.deleted?
|
338
|
+
|
339
|
+
object = ParanoidString.first
|
340
|
+
object.destroy_fully!
|
341
|
+
assert object.deleted?
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_deleted_fully?
|
345
|
+
ParanoidTime.first.destroy
|
346
|
+
assert_not ParanoidTime.with_deleted.first.deleted_fully?
|
347
|
+
|
348
|
+
ParanoidString.first.destroy
|
349
|
+
assert ParanoidString.with_deleted.first.deleted?
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_delete_deleted_fully?
|
353
|
+
ParanoidTime.first.delete
|
354
|
+
assert_not ParanoidTime.with_deleted.first.deleted_fully?
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_destroy_fully_deleted_fully?
|
358
|
+
object = ParanoidTime.first
|
359
|
+
object.destroy_fully!
|
360
|
+
assert object.deleted_fully?
|
361
|
+
end
|
362
|
+
|
276
363
|
def test_paranoid_destroy_callbacks
|
277
364
|
@paranoid_with_callback = ParanoidWithCallback.first
|
278
365
|
ParanoidWithCallback.transaction do
|
@@ -312,6 +399,14 @@ class ParanoidTest < ParanoidBaseTest
|
|
312
399
|
assert @paranoid_with_callback.called_after_recover
|
313
400
|
end
|
314
401
|
|
402
|
+
def test_recovery_callbacks_without_destroy
|
403
|
+
@paranoid_with_callback = ParanoidWithCallback.first
|
404
|
+
@paranoid_with_callback.recover
|
405
|
+
|
406
|
+
assert_nil @paranoid_with_callback.called_before_recover
|
407
|
+
assert_nil @paranoid_with_callback.called_after_recover
|
408
|
+
end
|
409
|
+
|
315
410
|
def test_delete_by_multiple_id_is_paranoid
|
316
411
|
model_a = ParanoidBelongsDependant.create
|
317
412
|
model_b = ParanoidBelongsDependant.create
|
@@ -360,81 +455,207 @@ class ParanoidTest < ParanoidBaseTest
|
|
360
455
|
|
361
456
|
# Test string type columns that don't have a nil value when not deleted (Y/N for example)
|
362
457
|
def test_string_type_with_no_nil_value_before_destroy
|
363
|
-
ps = ParanoidString.create!(:
|
364
|
-
assert_equal 1, ParanoidString.where(:
|
458
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
459
|
+
assert_equal 1, ParanoidString.where(id: ps).count
|
365
460
|
end
|
366
461
|
|
367
462
|
def test_string_type_with_no_nil_value_after_destroy
|
368
|
-
ps = ParanoidString.create!(:
|
463
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
369
464
|
ps.destroy
|
370
|
-
assert_equal 0, ParanoidString.where(:
|
465
|
+
assert_equal 0, ParanoidString.where(id: ps).count
|
371
466
|
end
|
372
467
|
|
373
468
|
def test_string_type_with_no_nil_value_before_destroy_with_deleted
|
374
|
-
ps = ParanoidString.create!(:
|
375
|
-
assert_equal 1, ParanoidString.with_deleted.where(:
|
469
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
470
|
+
assert_equal 1, ParanoidString.with_deleted.where(id: ps).count
|
376
471
|
end
|
377
472
|
|
378
473
|
def test_string_type_with_no_nil_value_after_destroy_with_deleted
|
379
|
-
ps = ParanoidString.create!(:
|
474
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
380
475
|
ps.destroy
|
381
|
-
assert_equal 1, ParanoidString.with_deleted.where(:
|
476
|
+
assert_equal 1, ParanoidString.with_deleted.where(id: ps).count
|
382
477
|
end
|
383
478
|
|
384
479
|
def test_string_type_with_no_nil_value_before_destroy_only_deleted
|
385
|
-
ps = ParanoidString.create!(:
|
386
|
-
assert_equal 0, ParanoidString.only_deleted.where(:
|
480
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
481
|
+
assert_equal 0, ParanoidString.only_deleted.where(id: ps).count
|
387
482
|
end
|
388
483
|
|
389
484
|
def test_string_type_with_no_nil_value_after_destroy_only_deleted
|
390
|
-
ps = ParanoidString.create!(:
|
485
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
391
486
|
ps.destroy
|
392
|
-
assert_equal 1, ParanoidString.only_deleted.where(:
|
487
|
+
assert_equal 1, ParanoidString.only_deleted.where(id: ps).count
|
393
488
|
end
|
394
489
|
|
395
490
|
def test_string_type_with_no_nil_value_after_destroyed_twice
|
396
|
-
ps = ParanoidString.create!(:
|
491
|
+
ps = ParanoidString.create!(deleted: "not dead")
|
397
492
|
2.times { ps.destroy }
|
398
|
-
assert_equal 0, ParanoidString.with_deleted.where(:
|
493
|
+
assert_equal 0, ParanoidString.with_deleted.where(id: ps).count
|
399
494
|
end
|
400
495
|
|
401
496
|
# Test boolean type columns, that are not nullable
|
402
497
|
def test_boolean_type_with_no_nil_value_before_destroy
|
403
|
-
ps = ParanoidBooleanNotNullable.create!
|
404
|
-
assert_equal 1, ParanoidBooleanNotNullable.where(:
|
498
|
+
ps = ParanoidBooleanNotNullable.create!
|
499
|
+
assert_equal 1, ParanoidBooleanNotNullable.where(id: ps).count
|
405
500
|
end
|
406
501
|
|
407
502
|
def test_boolean_type_with_no_nil_value_after_destroy
|
408
|
-
ps = ParanoidBooleanNotNullable.create!
|
503
|
+
ps = ParanoidBooleanNotNullable.create!
|
409
504
|
ps.destroy
|
410
|
-
assert_equal 0, ParanoidBooleanNotNullable.where(:
|
505
|
+
assert_equal 0, ParanoidBooleanNotNullable.where(id: ps).count
|
411
506
|
end
|
412
507
|
|
413
508
|
def test_boolean_type_with_no_nil_value_before_destroy_with_deleted
|
414
|
-
ps = ParanoidBooleanNotNullable.create!
|
415
|
-
assert_equal 1, ParanoidBooleanNotNullable.with_deleted.where(:
|
509
|
+
ps = ParanoidBooleanNotNullable.create!
|
510
|
+
assert_equal 1, ParanoidBooleanNotNullable.with_deleted.where(id: ps).count
|
416
511
|
end
|
417
512
|
|
418
513
|
def test_boolean_type_with_no_nil_value_after_destroy_with_deleted
|
419
|
-
ps = ParanoidBooleanNotNullable.create!
|
514
|
+
ps = ParanoidBooleanNotNullable.create!
|
420
515
|
ps.destroy
|
421
|
-
assert_equal 1, ParanoidBooleanNotNullable.with_deleted.where(:
|
516
|
+
assert_equal 1, ParanoidBooleanNotNullable.with_deleted.where(id: ps).count
|
422
517
|
end
|
423
518
|
|
424
519
|
def test_boolean_type_with_no_nil_value_before_destroy_only_deleted
|
425
|
-
ps = ParanoidBooleanNotNullable.create!
|
426
|
-
assert_equal 0, ParanoidBooleanNotNullable.only_deleted.where(:
|
520
|
+
ps = ParanoidBooleanNotNullable.create!
|
521
|
+
assert_equal 0, ParanoidBooleanNotNullable.only_deleted.where(id: ps).count
|
427
522
|
end
|
428
523
|
|
429
524
|
def test_boolean_type_with_no_nil_value_after_destroy_only_deleted
|
430
|
-
ps = ParanoidBooleanNotNullable.create!
|
525
|
+
ps = ParanoidBooleanNotNullable.create!
|
431
526
|
ps.destroy
|
432
|
-
assert_equal 1, ParanoidBooleanNotNullable.only_deleted.where(:
|
527
|
+
assert_equal 1, ParanoidBooleanNotNullable.only_deleted.where(id: ps).count
|
433
528
|
end
|
434
529
|
|
435
530
|
def test_boolean_type_with_no_nil_value_after_destroyed_twice
|
436
|
-
ps = ParanoidBooleanNotNullable.create!
|
531
|
+
ps = ParanoidBooleanNotNullable.create!
|
532
|
+
2.times { ps.destroy }
|
533
|
+
assert_equal 0, ParanoidBooleanNotNullable.with_deleted.where(id: ps).count
|
534
|
+
end
|
535
|
+
|
536
|
+
def test_no_double_tap_destroys_fully
|
537
|
+
ps = ParanoidNoDoubleTapDestroysFully.create!
|
437
538
|
2.times { ps.destroy }
|
438
|
-
assert_equal
|
539
|
+
assert_equal 1, ParanoidNoDoubleTapDestroysFully.with_deleted.where(id: ps).count
|
540
|
+
end
|
541
|
+
|
542
|
+
def test_decrement_counters_without_touch
|
543
|
+
paranoid_boolean = ParanoidBoolean.create!
|
544
|
+
paranoid_with_counter_cache = ParanoidWithCounterCache
|
545
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
546
|
+
|
547
|
+
assert_equal 1, paranoid_boolean.paranoid_with_counter_caches_count
|
548
|
+
updated_at = paranoid_boolean.reload.updated_at
|
549
|
+
|
550
|
+
paranoid_with_counter_cache.destroy
|
551
|
+
|
552
|
+
assert_equal 0, paranoid_boolean.reload.paranoid_with_counter_caches_count
|
553
|
+
assert_equal updated_at, paranoid_boolean.reload.updated_at
|
554
|
+
end
|
555
|
+
|
556
|
+
def test_decrement_custom_counters
|
557
|
+
paranoid_boolean = ParanoidBoolean.create!
|
558
|
+
paranoid_with_custom_counter_cache = ParanoidWithCustomCounterCache
|
559
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
560
|
+
|
561
|
+
assert_equal 1, paranoid_boolean.custom_counter_cache
|
562
|
+
|
563
|
+
paranoid_with_custom_counter_cache.destroy
|
564
|
+
|
565
|
+
assert_equal 0, paranoid_boolean.reload.custom_counter_cache
|
566
|
+
end
|
567
|
+
|
568
|
+
def test_decrement_counters_with_touch
|
569
|
+
paranoid_boolean = ParanoidBoolean.create!
|
570
|
+
paranoid_with_counter_cache = ParanoidWithTouchAndCounterCache
|
571
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
572
|
+
|
573
|
+
assert_equal 1, paranoid_boolean.paranoid_with_touch_and_counter_caches_count
|
574
|
+
updated_at = paranoid_boolean.reload.updated_at
|
575
|
+
|
576
|
+
paranoid_with_counter_cache.destroy
|
577
|
+
|
578
|
+
assert_equal 0, paranoid_boolean.reload.paranoid_with_touch_and_counter_caches_count
|
579
|
+
assert_not_equal updated_at, paranoid_boolean.reload.updated_at
|
580
|
+
end
|
581
|
+
|
582
|
+
def test_touch_belongs_to
|
583
|
+
paranoid_boolean = ParanoidBoolean.create!
|
584
|
+
paranoid_with_counter_cache = ParanoidWithTouch
|
585
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
586
|
+
|
587
|
+
updated_at = paranoid_boolean.reload.updated_at
|
588
|
+
|
589
|
+
paranoid_with_counter_cache.destroy
|
590
|
+
|
591
|
+
assert_not_equal updated_at, paranoid_boolean.reload.updated_at
|
592
|
+
end
|
593
|
+
|
594
|
+
def test_destroy_with_optional_belongs_to_and_counter_cache
|
595
|
+
ps = ParanoidWithCounterCacheOnOptionalBelognsTo.create!
|
596
|
+
ps.destroy
|
597
|
+
assert_equal 1, ParanoidWithCounterCacheOnOptionalBelognsTo.only_deleted
|
598
|
+
.where(id: ps).count
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_hard_destroy_decrement_counters
|
602
|
+
paranoid_boolean = ParanoidBoolean.create!
|
603
|
+
paranoid_with_counter_cache = ParanoidWithCounterCache
|
604
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
605
|
+
|
606
|
+
assert_equal 1, paranoid_boolean.paranoid_with_counter_caches_count
|
607
|
+
|
608
|
+
paranoid_with_counter_cache.destroy_fully!
|
609
|
+
|
610
|
+
assert_equal 0, paranoid_boolean.reload.paranoid_with_counter_caches_count
|
611
|
+
end
|
612
|
+
|
613
|
+
def test_hard_destroy_decrement_custom_counters
|
614
|
+
paranoid_boolean = ParanoidBoolean.create!
|
615
|
+
paranoid_with_custom_counter_cache = ParanoidWithCustomCounterCache
|
616
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
617
|
+
|
618
|
+
assert_equal 1, paranoid_boolean.custom_counter_cache
|
619
|
+
|
620
|
+
paranoid_with_custom_counter_cache.destroy_fully!
|
621
|
+
|
622
|
+
assert_equal 0, paranoid_boolean.reload.custom_counter_cache
|
623
|
+
end
|
624
|
+
|
625
|
+
def test_increment_counters
|
626
|
+
paranoid_boolean = ParanoidBoolean.create!
|
627
|
+
paranoid_with_counter_cache = ParanoidWithCounterCache
|
628
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
629
|
+
|
630
|
+
assert_equal 1, paranoid_boolean.paranoid_with_counter_caches_count
|
631
|
+
|
632
|
+
paranoid_with_counter_cache.destroy
|
633
|
+
|
634
|
+
assert_equal 0, paranoid_boolean.reload.paranoid_with_counter_caches_count
|
635
|
+
|
636
|
+
paranoid_with_counter_cache.recover
|
637
|
+
|
638
|
+
assert_equal 1, paranoid_boolean.reload.paranoid_with_counter_caches_count
|
639
|
+
end
|
640
|
+
|
641
|
+
def test_increment_custom_counters
|
642
|
+
paranoid_boolean = ParanoidBoolean.create!
|
643
|
+
paranoid_with_custom_counter_cache = ParanoidWithCustomCounterCache
|
644
|
+
.create!(paranoid_boolean: paranoid_boolean)
|
645
|
+
|
646
|
+
assert_equal 1, paranoid_boolean.custom_counter_cache
|
647
|
+
|
648
|
+
paranoid_with_custom_counter_cache.destroy
|
649
|
+
|
650
|
+
assert_equal 0, paranoid_boolean.reload.custom_counter_cache
|
651
|
+
|
652
|
+
paranoid_with_custom_counter_cache.recover
|
653
|
+
|
654
|
+
assert_equal 1, paranoid_boolean.reload.custom_counter_cache
|
655
|
+
end
|
656
|
+
|
657
|
+
def test_explicitly_setting_table_name_after_acts_as_paranoid_macro
|
658
|
+
assert_equal "explicit_table.deleted_at", ParanoidWithExplicitTableNameAfterMacro
|
659
|
+
.paranoid_column_reference
|
439
660
|
end
|
440
661
|
end
|