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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4840070148649d6ad07f0342b48a031fdf25827
4
- data.tar.gz: 25ae25c52215d9cc78ab55756baa09f79255b283
3
+ metadata.gz: a081d1169b0d0b18a5815aafe4bafdeab81e62fd
4
+ data.tar.gz: 4b38ec1db06051b0c5ada74f9405f935ba39624b
5
5
  SHA512:
6
- metadata.gz: ea4f3ab508171f21e047ded352fabb8b0f6f5821746054d00dcc5b733f3150f069086ccdbf892ad3c79aec071609839dba4676eaab73941f7b2b23b49639b46c
7
- data.tar.gz: 732a2fe402b9d718cecf2968068adf2a83c7486cac87127684d92736b0d39b9352a433ae69e062c90665fd4b93a5cb4cbfe40d38d3f46a1efaf4b9374185bb2c
6
+ metadata.gz: e80496f3e472a7ecef7abee20f49d394fb884bb8e81313c92e6f1915b2f805d9f14ef1ef930f47ccdf97300df51f25458881d465df4355f85d2a6066c0b92671
7
+ data.tar.gz: 205530a0638b6d1d1f455cfae490e2c9e77f080ef4fdfd63d6fdafba849ebc7615ff34f091479b011a02cd9bd7919f27061a0f608be33be22b9801041d8277b7
@@ -3,20 +3,24 @@ language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
5
  - 2.1.10
6
- - 2.2.5
7
- - 2.3.1
8
- - jruby-9.1.0.0
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.15'
13
- - RAILS='~> 4.2.6'
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='~> 5.0.0'
22
- rvm: jruby-9.1.0.0
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
@@ -1,6 +1,28 @@
1
1
  # paranoia Changelog
2
2
 
3
- ## 2.2.0 (unreleased)
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, otherwise the normal destroy will be called.
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:
@@ -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
- quoted_paranoia_column = connection.quote_column_name(paranoia_column)
39
- with_deleted.where("#{quoted_paranoia_column} IS NULL OR #{quoted_paranoia_column} != ?", paranoia_sentinel_value)
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
- class ActiveRecord::Base
209
- def self.acts_as_paranoid(options={})
210
- alias_method :really_destroyed?, :destroyed?
211
- alias_method :really_delete, :delete
212
- alias_method :destroy_without_paranoia, :destroy
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
- include Paranoia
215
- class_attribute :paranoia_column, :paranoia_sentinel_value
219
+ include Paranoia
220
+ class_attribute :paranoia_column, :paranoia_sentinel_value
216
221
 
217
- self.paranoia_column = (options[:column] || :deleted_at).to_s
218
- self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }
219
- def self.paranoia_scope
220
- where(paranoia_column => paranoia_sentinel_value)
221
- end
222
- class << self; alias_method :without_deleted, :paranoia_scope end
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
- unless options[:without_default_scope]
225
- default_scope { paranoia_scope }
226
- end
229
+ unless options[:without_default_scope]
230
+ default_scope { paranoia_scope }
231
+ end
227
232
 
228
- before_restore {
229
- self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers)
230
- }
231
- after_restore {
232
- self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers)
233
- }
234
- end
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
- # Please do not use this method in production.
237
- # Pretty please.
238
- def self.I_AM_THE_DESTROYER!
239
- # TODO: actually implement spelling error fixes
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
- end
250
+ end
246
251
 
247
- def self.paranoid? ; false ; end
248
- def paranoid? ; self.class.paranoid? ; end
252
+ def self.paranoid? ; false ; end
253
+ def paranoid? ; self.class.paranoid? ; end
249
254
 
250
- private
255
+ private
251
256
 
252
- def paranoia_column
253
- self.class.paranoia_column
254
- end
257
+ def paranoia_column
258
+ self.class.paranoia_column
259
+ end
255
260
 
256
- def paranoia_sentinel_value
257
- self.class.paranoia_sentinel_value
261
+ def paranoia_sentinel_value
262
+ self.class.paranoia_sentinel_value
263
+ end
258
264
  end
259
265
  end
260
266
 
@@ -1,3 +1,3 @@
1
1
  module Paranoia
2
- VERSION = "2.2.0"
2
+ VERSION = '2.2.1'.freeze
3
3
  end
@@ -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.0
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: 2016-10-20 00:00:00.000000000 Z
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.5.1
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,