paranoia 2.2.0 → 2.2.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/.travis.yml +13 -9
- data/CHANGELOG.md +23 -1
- data/README.md +72 -1
- data/lib/paranoia.rb +47 -41
- data/lib/paranoia/version.rb +1 -1
- data/test/paranoia_test.rb +62 -0
- 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: a081d1169b0d0b18a5815aafe4bafdeab81e62fd
|
4
|
+
data.tar.gz: 4b38ec1db06051b0c5ada74f9405f935ba39624b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e80496f3e472a7ecef7abee20f49d394fb884bb8e81313c92e6f1915b2f805d9f14ef1ef930f47ccdf97300df51f25458881d465df4355f85d2a6066c0b92671
|
7
|
+
data.tar.gz: 205530a0638b6d1d1f455cfae490e2c9e77f080ef4fdfd63d6fdafba849ebc7615ff34f091479b011a02cd9bd7919f27061a0f608be33be22b9801041d8277b7
|
data/.travis.yml
CHANGED
@@ -3,20 +3,24 @@ language: ruby
|
|
3
3
|
cache: bundler
|
4
4
|
rvm:
|
5
5
|
- 2.1.10
|
6
|
-
- 2.2.
|
7
|
-
- 2.3.
|
8
|
-
- jruby-9.1.
|
6
|
+
- 2.2.6
|
7
|
+
- 2.3.3
|
8
|
+
- jruby-9.1.6.0
|
9
9
|
|
10
10
|
env:
|
11
11
|
matrix:
|
12
|
-
- RAILS='~> 4.1.
|
13
|
-
- RAILS='~> 4.2.
|
14
|
-
- RAILS='~> 5.0.0'
|
12
|
+
- RAILS='~> 4.1.16'
|
13
|
+
- RAILS='~> 4.2.7.1'
|
14
|
+
- RAILS='~> 5.0.0.1'
|
15
15
|
|
16
16
|
matrix:
|
17
17
|
exclude:
|
18
|
-
- env: RAILS='~> 5.0.0'
|
18
|
+
- env: RAILS='~> 5.0.0.1'
|
19
19
|
rvm: 2.1.10
|
20
20
|
allow_failures:
|
21
|
-
- env: RAILS='~>
|
22
|
-
rvm: jruby-9.1.
|
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
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,28 @@
|
|
1
1
|
# paranoia Changelog
|
2
2
|
|
3
|
-
## 2.2.
|
3
|
+
## 2.2.2 (Unreleased)
|
4
|
+
|
5
|
+
## 2.2.1 (2017-02-15)
|
6
|
+
|
7
|
+
* [#371](https://github.com/rubysherpas/paranoia/pull/371) Use ActiveSupport.on_load to correctly re-open ActiveRecord::Base
|
8
|
+
|
9
|
+
_Fixes [#335](https://github.com/rubysherpas/paranoia/issues/335) and [#381](https://github.com/rubysherpas/paranoia/issues/381)._
|
10
|
+
|
11
|
+
[Iaan Krynauw (@iaankrynauw)](https://github.com/iaankrynauw)
|
12
|
+
|
13
|
+
* [#377](https://github.com/rubysherpas/paranoia/pull/377) Touch record on paranoia-destroy.
|
14
|
+
|
15
|
+
_Fixes [#296](https://github.com/rubysherpas/paranoia/issues/296)._
|
16
|
+
|
17
|
+
[René (@rbr)](https://github.com/rbr)
|
18
|
+
|
19
|
+
* [#379](https://github.com/rubysherpas/paranoia/pull/379) Fixes a problem of ambiguous table names when using only_deleted method.
|
20
|
+
|
21
|
+
_Fixes [#26](https://github.com/rubysherpas/paranoia/issues/26) and [#27](https://github.com/rubysherpas/paranoia/pull/27)._
|
22
|
+
|
23
|
+
[Thomas Romera (@Erowlin)](https://github.com/Erowlin)
|
24
|
+
|
25
|
+
## 2.2.0 (2016-10-21)
|
4
26
|
|
5
27
|
* Ruby 2.0 or greater is required
|
6
28
|
* Rails 5.0.0.beta1.1 support [@pigeonworks](https://github.com/pigeonworks) [@halostatue](https://github.com/halostatue) and [@gagalago](https://github.com/gagalago)
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ When your app is using Paranoia, calling `destroy` on an ActiveRecord object doe
|
|
6
6
|
|
7
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 if `acts_as_paranoid` is set,
|
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. ***See [Destroying through association callbacks](#destroying-through-association-callbacks) for clarifying examples.***
|
10
10
|
|
11
11
|
## Getting Started Video
|
12
12
|
Setup and basic usage of the paranoia gem
|
@@ -245,6 +245,77 @@ class Client < ActiveRecord::Base
|
|
245
245
|
end
|
246
246
|
```
|
247
247
|
|
248
|
+
##### Destroying through association callbacks
|
249
|
+
|
250
|
+
When dealing with `dependent: :destroy` associations and `acts_as_paranoid`, it's important to remember that whatever method is called on the parent model will be called on the child model. For example, given both models of an association have `acts_as_paranoid` defined:
|
251
|
+
|
252
|
+
``` ruby
|
253
|
+
class Client < ActiveRecord::Base
|
254
|
+
acts_as_paranoid
|
255
|
+
|
256
|
+
has_many :emails, dependent: :destroy
|
257
|
+
end
|
258
|
+
|
259
|
+
class Email < ActiveRecord::Base
|
260
|
+
acts_as_paranoid
|
261
|
+
|
262
|
+
belongs_to :client
|
263
|
+
end
|
264
|
+
```
|
265
|
+
|
266
|
+
When we call `destroy` on the parent `client`, it will call `destroy` on all of its associated children `emails`:
|
267
|
+
|
268
|
+
``` ruby
|
269
|
+
>> client.emails.count
|
270
|
+
# => 5
|
271
|
+
>> client.destroy
|
272
|
+
# => client
|
273
|
+
>> client.deleted_at
|
274
|
+
# => [current timestamp]
|
275
|
+
>> Email.where(client_id: client.id).count
|
276
|
+
# => 0
|
277
|
+
>> Email.with_deleted.where(client_id: client.id).count
|
278
|
+
# => 5
|
279
|
+
```
|
280
|
+
|
281
|
+
Similarly, when we call `really_destroy!` on the parent `client`, then each child `email` will also have `really_destroy!` called:
|
282
|
+
|
283
|
+
``` ruby
|
284
|
+
>> client.emails.count
|
285
|
+
# => 5
|
286
|
+
>> client.id
|
287
|
+
# => 12345
|
288
|
+
>> client.really_destroy!
|
289
|
+
# => client
|
290
|
+
>> Client.find 12345
|
291
|
+
# => ActiveRecord::RecordNotFound
|
292
|
+
>> Email.with_deleted.where(client_id: client.id).count
|
293
|
+
# => 0
|
294
|
+
```
|
295
|
+
|
296
|
+
However, if the child model `Email` does not have `acts_as_paranoid` set, then calling `destroy` on the parent `client` will also call `destroy` on each child `email`, thereby actually destroying them:
|
297
|
+
|
298
|
+
``` ruby
|
299
|
+
class Client < ActiveRecord::Base
|
300
|
+
acts_as_paranoid
|
301
|
+
|
302
|
+
has_many :emails, dependent: :destroy
|
303
|
+
end
|
304
|
+
|
305
|
+
class Email < ActiveRecord::Base
|
306
|
+
belongs_to :client
|
307
|
+
end
|
308
|
+
|
309
|
+
>> client.emails.count
|
310
|
+
# => 5
|
311
|
+
>> client.destroy
|
312
|
+
# => client
|
313
|
+
>> Email.where(client_id: client.id).count
|
314
|
+
# => 0
|
315
|
+
>> Email.with_deleted.where(client_id: client.id).count
|
316
|
+
# => NoMethodError: undefined method `with_deleted' for #<Class:0x0123456>
|
317
|
+
```
|
318
|
+
|
248
319
|
## Acts As Paranoid Migration
|
249
320
|
|
250
321
|
You can replace the older `acts_as_paranoid` methods as follows:
|
data/lib/paranoia.rb
CHANGED
@@ -35,8 +35,9 @@ module Paranoia
|
|
35
35
|
# some deleted rows will hold a null value in the paranoia column
|
36
36
|
# these will not match != sentinel value because "NULL != value" is
|
37
37
|
# NULL under the sql standard
|
38
|
-
|
39
|
-
|
38
|
+
# 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)}"
|
40
|
+
with_deleted.where("#{scoped_quoted_paranoia_column} IS NULL OR #{scoped_quoted_paranoia_column} != ?", paranoia_sentinel_value)
|
40
41
|
end
|
41
42
|
alias_method :deleted, :only_deleted
|
42
43
|
|
@@ -110,7 +111,6 @@ module Paranoia
|
|
110
111
|
if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
|
111
112
|
write_attribute paranoia_column, paranoia_sentinel_value
|
112
113
|
update_columns(paranoia_restore_attributes)
|
113
|
-
touch
|
114
114
|
end
|
115
115
|
restore_associated_records if opts[:recursive]
|
116
116
|
end
|
@@ -154,13 +154,17 @@ module Paranoia
|
|
154
154
|
def paranoia_restore_attributes
|
155
155
|
{
|
156
156
|
paranoia_column => paranoia_sentinel_value
|
157
|
-
}
|
157
|
+
}.merge(timestamp_attributes_with_current_time)
|
158
158
|
end
|
159
159
|
|
160
160
|
def paranoia_destroy_attributes
|
161
161
|
{
|
162
162
|
paranoia_column => current_time_from_proper_timezone
|
163
|
-
}
|
163
|
+
}.merge(timestamp_attributes_with_current_time)
|
164
|
+
end
|
165
|
+
|
166
|
+
def timestamp_attributes_with_current_time
|
167
|
+
timestamp_attributes_for_update_in_model.each_with_object({}) { |attr,hash| hash[attr] = current_time_from_proper_timezone }
|
164
168
|
end
|
165
169
|
|
166
170
|
# restore associated records that have been soft deleted when
|
@@ -205,56 +209,58 @@ module Paranoia
|
|
205
209
|
end
|
206
210
|
end
|
207
211
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
212
|
+
ActiveSupport.on_load(:active_record) do
|
213
|
+
class ActiveRecord::Base
|
214
|
+
def self.acts_as_paranoid(options={})
|
215
|
+
alias_method :really_destroyed?, :destroyed?
|
216
|
+
alias_method :really_delete, :delete
|
217
|
+
alias_method :destroy_without_paranoia, :destroy
|
213
218
|
|
214
|
-
|
215
|
-
|
219
|
+
include Paranoia
|
220
|
+
class_attribute :paranoia_column, :paranoia_sentinel_value
|
216
221
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
222
|
+
self.paranoia_column = (options[:column] || :deleted_at).to_s
|
223
|
+
self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }
|
224
|
+
def self.paranoia_scope
|
225
|
+
where(paranoia_column => paranoia_sentinel_value)
|
226
|
+
end
|
227
|
+
class << self; alias_method :without_deleted, :paranoia_scope end
|
223
228
|
|
224
|
-
|
225
|
-
|
226
|
-
|
229
|
+
unless options[:without_default_scope]
|
230
|
+
default_scope { paranoia_scope }
|
231
|
+
end
|
227
232
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
233
|
+
before_restore {
|
234
|
+
self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers)
|
235
|
+
}
|
236
|
+
after_restore {
|
237
|
+
self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers)
|
238
|
+
}
|
239
|
+
end
|
235
240
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
241
|
+
# Please do not use this method in production.
|
242
|
+
# Pretty please.
|
243
|
+
def self.I_AM_THE_DESTROYER!
|
244
|
+
# TODO: actually implement spelling error fixes
|
240
245
|
puts %Q{
|
241
246
|
Sharon: "There should be a method called I_AM_THE_DESTROYER!"
|
242
247
|
Ryan: "What should this method do?"
|
243
248
|
Sharon: "It should fix all the spelling errors on the page!"
|
244
249
|
}
|
245
|
-
|
250
|
+
end
|
246
251
|
|
247
|
-
|
248
|
-
|
252
|
+
def self.paranoid? ; false ; end
|
253
|
+
def paranoid? ; self.class.paranoid? ; end
|
249
254
|
|
250
|
-
|
255
|
+
private
|
251
256
|
|
252
|
-
|
253
|
-
|
254
|
-
|
257
|
+
def paranoia_column
|
258
|
+
self.class.paranoia_column
|
259
|
+
end
|
255
260
|
|
256
|
-
|
257
|
-
|
261
|
+
def paranoia_sentinel_value
|
262
|
+
self.class.paranoia_sentinel_value
|
263
|
+
end
|
258
264
|
end
|
259
265
|
end
|
260
266
|
|
data/lib/paranoia/version.rb
CHANGED
data/test/paranoia_test.rb
CHANGED
@@ -40,6 +40,8 @@ def setup!
|
|
40
40
|
'unparanoid_unique_models' => 'name VARCHAR(32), paranoid_with_unparanoids_id INTEGER',
|
41
41
|
'active_column_models' => 'deleted_at DATETIME, active BOOLEAN',
|
42
42
|
'active_column_model_with_uniqueness_validations' => 'name VARCHAR(32), deleted_at DATETIME, active BOOLEAN',
|
43
|
+
'paranoid_model_with_belongs_to_active_column_model_with_has_many_relationships' => 'name VARCHAR(32), deleted_at DATETIME, active BOOLEAN, active_column_model_with_has_many_relationship_id INTEGER',
|
44
|
+
'active_column_model_with_has_many_relationships' => 'name VARCHAR(32), deleted_at DATETIME, active BOOLEAN',
|
43
45
|
'without_default_scope_models' => 'deleted_at DATETIME'
|
44
46
|
}.each do |table_name, columns_as_sql_string|
|
45
47
|
ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
|
@@ -182,8 +184,11 @@ class ParanoiaTest < test_framework
|
|
182
184
|
p2 = ParanoidModel.create(:parent_model => parent2)
|
183
185
|
p1.destroy
|
184
186
|
p2.destroy
|
187
|
+
|
185
188
|
assert_equal 0, parent1.paranoid_models.count
|
186
189
|
assert_equal 1, parent1.paranoid_models.only_deleted.count
|
190
|
+
|
191
|
+
assert_equal 2, ParanoidModel.only_deleted.joins(:parent_model).count
|
187
192
|
assert_equal 1, parent1.paranoid_models.deleted.count
|
188
193
|
assert_equal 0, parent1.paranoid_models.without_deleted.count
|
189
194
|
p3 = ParanoidModel.create(:parent_model => parent1)
|
@@ -192,6 +197,17 @@ class ParanoiaTest < test_framework
|
|
192
197
|
assert_equal [p1,p3], parent1.paranoid_models.with_deleted
|
193
198
|
end
|
194
199
|
|
200
|
+
def test_only_deleted_with_joins
|
201
|
+
c1 = ActiveColumnModelWithHasManyRelationship.create(name: 'Jacky')
|
202
|
+
c2 = ActiveColumnModelWithHasManyRelationship.create(name: 'Thomas')
|
203
|
+
p1 = ParanoidModelWithBelongsToActiveColumnModelWithHasManyRelationship.create(name: 'Hello', active_column_model_with_has_many_relationship: c1)
|
204
|
+
|
205
|
+
c1.destroy
|
206
|
+
assert_equal 1, ActiveColumnModelWithHasManyRelationship.count
|
207
|
+
assert_equal 1, ActiveColumnModelWithHasManyRelationship.only_deleted.count
|
208
|
+
assert_equal 1, ActiveColumnModelWithHasManyRelationship.only_deleted.joins(:paranoid_model_with_belongs_to_active_column_model_with_has_many_relationships).count
|
209
|
+
end
|
210
|
+
|
195
211
|
def test_destroy_behavior_for_custom_column_models
|
196
212
|
model = CustomColumnModel.new
|
197
213
|
assert_equal 0, model.class.count
|
@@ -774,6 +790,13 @@ class ParanoiaTest < test_framework
|
|
774
790
|
refute b.valid?
|
775
791
|
end
|
776
792
|
|
793
|
+
def test_updated_at_modification_on_destroy
|
794
|
+
paranoid_model = ParanoidModelWithTimestamp.create(:parent_model => ParentModel.create, :updated_at => 1.day.ago)
|
795
|
+
assert paranoid_model.updated_at < 10.minutes.ago
|
796
|
+
paranoid_model.destroy
|
797
|
+
assert paranoid_model.updated_at > 10.minutes.ago
|
798
|
+
end
|
799
|
+
|
777
800
|
def test_updated_at_modification_on_restore
|
778
801
|
parent1 = ParentModel.create
|
779
802
|
pt1 = ParanoidModelWithTimestamp.create(:parent_model => parent1)
|
@@ -1105,6 +1128,45 @@ class ActiveColumnModelWithUniquenessValidation < ActiveRecord::Base
|
|
1105
1128
|
end
|
1106
1129
|
end
|
1107
1130
|
|
1131
|
+
class ActiveColumnModelWithHasManyRelationship < ActiveRecord::Base
|
1132
|
+
has_many :paranoid_model_with_belongs_to_active_column_model_with_has_many_relationships
|
1133
|
+
acts_as_paranoid column: :active, sentinel_value: true
|
1134
|
+
|
1135
|
+
def paranoia_restore_attributes
|
1136
|
+
{
|
1137
|
+
deleted_at: nil,
|
1138
|
+
active: true
|
1139
|
+
}
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def paranoia_destroy_attributes
|
1143
|
+
{
|
1144
|
+
deleted_at: current_time_from_proper_timezone,
|
1145
|
+
active: nil
|
1146
|
+
}
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
class ParanoidModelWithBelongsToActiveColumnModelWithHasManyRelationship < ActiveRecord::Base
|
1151
|
+
belongs_to :active_column_model_with_has_many_relationship
|
1152
|
+
|
1153
|
+
acts_as_paranoid column: :active, sentinel_value: true
|
1154
|
+
|
1155
|
+
def paranoia_restore_attributes
|
1156
|
+
{
|
1157
|
+
deleted_at: nil,
|
1158
|
+
active: true
|
1159
|
+
}
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
def paranoia_destroy_attributes
|
1163
|
+
{
|
1164
|
+
deleted_at: current_time_from_proper_timezone,
|
1165
|
+
active: nil
|
1166
|
+
}
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1108
1170
|
class NonParanoidModel < ActiveRecord::Base
|
1109
1171
|
end
|
1110
1172
|
|
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.2.
|
4
|
+
version: 2.2.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:
|
11
|
+
date: 2017-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
version: 1.3.6
|
107
107
|
requirements: []
|
108
108
|
rubyforge_project:
|
109
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.6.9
|
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,
|