paranoia 2.2.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,
|