paranoia 2.2.1 → 2.3.0

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: a081d1169b0d0b18a5815aafe4bafdeab81e62fd
4
- data.tar.gz: 4b38ec1db06051b0c5ada74f9405f935ba39624b
3
+ metadata.gz: 3d592d028e0a4ad7c1909649973803af1ef85102
4
+ data.tar.gz: a4fb1bb5daec2bd6b61c4beaa9b2ce2d415a2661
5
5
  SHA512:
6
- metadata.gz: e80496f3e472a7ecef7abee20f49d394fb884bb8e81313c92e6f1915b2f805d9f14ef1ef930f47ccdf97300df51f25458881d465df4355f85d2a6066c0b92671
7
- data.tar.gz: 205530a0638b6d1d1f455cfae490e2c9e77f080ef4fdfd63d6fdafba849ebc7615ff34f091479b011a02cd9bd7919f27061a0f608be33be22b9801041d8277b7
6
+ metadata.gz: 7a7d46b3e08208ae25969ddfe75d30ed0651ac649f834dd1ccb872197ce22ef93427281ce5c396c96d36a95f52ba53e54b81910970cedcd1ecd65d040502e819
7
+ data.tar.gz: 86866ca4cfd172783fbf7c7363ece9c1aea905129e210b228a315a34f2d2d6f343d5bbdd95cf96dfd8b3aa6d6d52e5391d4c026a84434a2f53fd6d23d37db6ea
@@ -2,25 +2,25 @@ sudo: false
2
2
  language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.1.10
6
5
  - 2.2.6
7
6
  - 2.3.3
7
+ - 2.4.1
8
8
  - jruby-9.1.6.0
9
9
 
10
10
  env:
11
11
  matrix:
12
- - RAILS='~> 4.1.16'
13
12
  - RAILS='~> 4.2.7.1'
14
13
  - RAILS='~> 5.0.0.1'
14
+ - RAILS='~> 5.1.0.rc1'
15
15
 
16
16
  matrix:
17
17
  exclude:
18
- - env: RAILS='~> 5.0.0.1'
19
- rvm: 2.1.10
18
+ - env: RAILS='~> 5.1.0.rc1'
19
+ rvm: 2.2.6
20
20
  allow_failures:
21
- - env: RAILS='~> 4.1.16'
22
- rvm: jruby-9.1.6.0
23
21
  - env: RAILS='~> 4.2.7.1'
24
22
  rvm: jruby-9.1.6.0
25
23
  - env: RAILS='~> 5.0.0.1'
26
24
  rvm: jruby-9.1.6.0
25
+ - env: RAILS='~> 5.1.0.rc1'
26
+ rvm: jruby-9.1.6.0
@@ -1,6 +1,31 @@
1
1
  # paranoia Changelog
2
2
 
3
- ## 2.2.2 (Unreleased)
3
+ ## 2.3.0 (2017-04-14)
4
+
5
+ * [#393](https://github.com/rubysherpas/paranoia/pull/393) Drop support for Rails 4.1 and begin supporting Rails 5.1.
6
+
7
+ [Miklós Fazekas (@mfazekas)](https://github.com/mfazekas)
8
+
9
+ * [#391](https://github.com/rubysherpas/paranoia/pull/391) Use Contributor Covenant Version 1.4
10
+
11
+ [Ben A. Morgan (@BenMorganIO)](https://github.com/BenMorganIO)
12
+
13
+ * [#390](https://github.com/rubysherpas/paranoia/pull/390) Fix counter cache with double destroy, really_destroy, and restore
14
+
15
+ [Chris Oliver (@excid3)](https://github.com/excid3)
16
+
17
+ * [#389](https://github.com/rubysherpas/paranoia/pull/389) Added association not soft destroyed validator
18
+
19
+ _Fixes [#380](https://github.com/rubysherpas/paranoia/issues/380)_
20
+
21
+ [Edward Poot (@edwardmp)](https://github.com/edwardmp)
22
+
23
+ * [#383](https://github.com/rubysherpas/paranoia/pull/383) Add recovery window feature
24
+
25
+ _Fixes [#359](https://github.com/rubysherpas/paranoia/issues/359)_
26
+
27
+ [Andrzej Piątyszek (@konto-andrzeja)](https://github.com/konto-andrzeja)
28
+
4
29
 
5
30
  ## 2.2.1 (2017-02-15)
6
31
 
@@ -46,7 +71,7 @@
46
71
 
47
72
  * `#destroyed?` is no longer overridden. Use `#paranoia_destroyed?` for the existing behaviour. [Washington Luiz](https://github.com/huoxito)
48
73
  * `#persisted?` is no longer overridden.
49
- * ActiveRecord 4.0 no longer has `#destroy!` as an alias for `#really_destroy`.
74
+ * ActiveRecord 4.0 no longer has `#destroy!` as an alias for `#really_destroy!`.
50
75
  * `#destroy` will now raise an exception if called on a readonly record.
51
76
  * `#destroy` on a hard deleted record is now a successful noop.
52
77
  * `#destroy` on a new record will set deleted_at (previously this raised an error)
@@ -54,7 +79,7 @@
54
79
 
55
80
  ### Bug Fixes
56
81
 
57
- * Calling `#destroy` twice will not hard-delete records. Use `#really_destroy` if this is desired.
82
+ * Calling `#destroy` twice will not hard-delete records. Use `#really_destroy!` if this is desired.
58
83
  * Fix errors on non-paranoid has_one dependent associations
59
84
 
60
85
  ## 2.0.5 (2015-01-22)
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at ben@benmorgan.io. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/README.md CHANGED
@@ -181,6 +181,21 @@ Client.restore(id, :recursive => true)
181
181
  client.restore(:recursive => true)
182
182
  ```
183
183
 
184
+ If you want to restore a record and only those dependently destroyed associated records that were deleted within 2 minutes of the object upon which they depend:
185
+
186
+ ``` ruby
187
+ Client.restore(id, :recursive => true. :recovery_window => 2.minutes)
188
+ # or
189
+ client.restore(:recursive => true, :recovery_window => 2.minutes)
190
+ ```
191
+
192
+ Note that by default paranoia will not prevent that a soft destroyed object can't be associated with another object of a different model.
193
+ A Rails validator is provided should you require this functionality:
194
+ ``` ruby
195
+ validates :some_assocation, association_not_soft_destroyed: true
196
+ ```
197
+ This validator makes sure that `some_assocation` is not soft destroyed. If the object is soft destroyed the main object is rendered invalid and an validation error is added.
198
+
184
199
  For more information, please look at the tests.
185
200
 
186
201
  #### About indexes:
@@ -76,6 +76,7 @@ module Paranoia
76
76
  def destroy
77
77
  transaction do
78
78
  run_callbacks(:destroy) do
79
+ @_disable_counter_cache = deleted?
79
80
  result = delete
80
81
  next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
81
82
  each_counter_cached_associations do |association|
@@ -84,6 +85,7 @@ module Paranoia
84
85
  next unless send(association.reflection.name)
85
86
  association.decrement_counters
86
87
  end
88
+ @_disable_counter_cache = false
87
89
  result
88
90
  end
89
91
  end
@@ -105,14 +107,22 @@ module Paranoia
105
107
  def restore!(opts = {})
106
108
  self.class.transaction do
107
109
  run_callbacks(:restore) do
110
+ recovery_window_range = get_recovery_window_range(opts)
108
111
  # Fixes a bug where the build would error because attributes were frozen.
109
112
  # This only happened on Rails versions earlier than 4.1.
110
113
  noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
111
- if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
114
+ if within_recovery_window?(recovery_window_range) && ((noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen)
115
+ @_disable_counter_cache = !deleted?
112
116
  write_attribute paranoia_column, paranoia_sentinel_value
113
117
  update_columns(paranoia_restore_attributes)
118
+ each_counter_cached_associations do |association|
119
+ if send(association.reflection.name)
120
+ association.increment_counters
121
+ end
122
+ end
123
+ @_disable_counter_cache = false
114
124
  end
115
- restore_associated_records if opts[:recursive]
125
+ restore_associated_records(recovery_window_range) if opts[:recursive]
116
126
  end
117
127
  end
118
128
 
@@ -120,6 +130,17 @@ module Paranoia
120
130
  end
121
131
  alias :restore :restore!
122
132
 
133
+ def get_recovery_window_range(opts)
134
+ return opts[:recovery_window_range] if opts[:recovery_window_range]
135
+ return unless opts[:recovery_window]
136
+ (deleted_at - opts[:recovery_window]..deleted_at + opts[:recovery_window])
137
+ end
138
+
139
+ def within_recovery_window?(recovery_window_range)
140
+ return true unless recovery_window_range
141
+ recovery_window_range.cover?(deleted_at)
142
+ end
143
+
123
144
  def paranoia_destroyed?
124
145
  send(paranoia_column) != paranoia_sentinel_value
125
146
  end
@@ -128,6 +149,7 @@ module Paranoia
128
149
  def really_destroy!
129
150
  transaction do
130
151
  run_callbacks(:real_destroy) do
152
+ @_disable_counter_cache = deleted?
131
153
  dependent_reflections = self.class.reflections.select do |name, reflection|
132
154
  reflection.options[:dependent] == :destroy
133
155
  end
@@ -151,6 +173,10 @@ module Paranoia
151
173
 
152
174
  private
153
175
 
176
+ def each_counter_cached_associations
177
+ !@_disable_counter_cache && defined?(super) ? super : []
178
+ end
179
+
154
180
  def paranoia_restore_attributes
155
181
  {
156
182
  paranoia_column => paranoia_sentinel_value
@@ -169,7 +195,7 @@ module Paranoia
169
195
 
170
196
  # restore associated records that have been soft deleted when
171
197
  # we called #destroy
172
- def restore_associated_records
198
+ def restore_associated_records(recovery_window_range = nil)
173
199
  destroyed_associations = self.class.reflect_on_all_associations.select do |association|
174
200
  association.options[:dependent] == :destroy
175
201
  end
@@ -180,9 +206,11 @@ module Paranoia
180
206
  unless association_data.nil?
181
207
  if association_data.paranoid?
182
208
  if association.collection?
183
- association_data.only_deleted.each { |record| record.restore(:recursive => true) }
209
+ association_data.only_deleted.each do |record|
210
+ record.restore(:recursive => true, :recovery_window_range => recovery_window_range)
211
+ end
184
212
  else
185
- association_data.restore(:recursive => true)
213
+ association_data.restore(:recursive => true, :recovery_window_range => recovery_window_range)
186
214
  end
187
215
  end
188
216
  end
@@ -200,7 +228,8 @@ module Paranoia
200
228
 
201
229
  association_class = association_class_name.constantize
202
230
  if association_class.paranoid?
203
- association_class.only_deleted.where(association_find_conditions).first.try!(:restore, recursive: true)
231
+ association_class.only_deleted.where(association_find_conditions).first
232
+ .try!(:restore, recursive: true, :recovery_window_range => recovery_window_range)
204
233
  end
205
234
  end
206
235
  end
@@ -269,8 +298,8 @@ require 'paranoia/rspec' if defined? RSpec
269
298
  module ActiveRecord
270
299
  module Validations
271
300
  module UniquenessParanoiaValidator
272
- def build_relation(klass, table, attribute, value)
273
- relation = super(klass, table, attribute, value)
301
+ def build_relation(klass, *args)
302
+ relation = super
274
303
  return relation unless klass.respond_to?(:paranoia_column)
275
304
  arel_paranoia_scope = klass.arel_table[klass.paranoia_column].eq(klass.paranoia_sentinel_value)
276
305
  if ActiveRecord::VERSION::STRING >= "5.0"
@@ -284,5 +313,14 @@ module ActiveRecord
284
313
  class UniquenessValidator < ActiveModel::EachValidator
285
314
  prepend UniquenessParanoiaValidator
286
315
  end
316
+
317
+ class AssociationNotSoftDestroyedValidator < ActiveModel::EachValidator
318
+ def validate_each(record, attribute, value)
319
+ # if association is soft destroyed, add an error
320
+ if value.present? && value.deleted?
321
+ record.errors[attribute] << 'has been soft-deleted'
322
+ end
323
+ end
324
+ end
287
325
  end
288
326
  end
@@ -1,3 +1,3 @@
1
1
  module Paranoia
2
- VERSION = '2.2.1'.freeze
2
+ VERSION = '2.3.0'.freeze
3
3
  end
@@ -21,6 +21,7 @@ def setup!
21
21
  'paranoid_model_with_foreign_key_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER',
22
22
  'paranoid_model_with_timestamps' => 'parent_model_id INTEGER, created_at DATETIME, updated_at DATETIME, deleted_at DATETIME',
23
23
  'not_paranoid_model_with_belongs' => 'parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER',
24
+ 'not_paranoid_model_with_belongs_and_assocation_not_soft_destroyed_validator' => 'parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER',
24
25
  'paranoid_model_with_has_one_and_builds' => 'parent_model_id INTEGER, color VARCHAR(32), deleted_at DATETIME, has_one_foreign_key_id INTEGER',
25
26
  'featureful_models' => 'deleted_at DATETIME, name VARCHAR(32)',
26
27
  'plain_models' => 'deleted_at DATETIME',
@@ -117,9 +118,9 @@ class ParanoiaTest < test_framework
117
118
  model.remove_called_variables # clear called callback flags
118
119
  model.destroy
119
120
 
120
- assert_equal nil, model.instance_variable_get(:@update_callback_called)
121
- assert_equal nil, model.instance_variable_get(:@save_callback_called)
122
- assert_equal nil, model.instance_variable_get(:@validate_called)
121
+ assert_nil model.instance_variable_get(:@update_callback_called)
122
+ assert_nil model.instance_variable_get(:@save_callback_called)
123
+ assert_nil model.instance_variable_get(:@validate_called)
123
124
 
124
125
  assert model.instance_variable_get(:@destroy_callback_called)
125
126
  assert model.instance_variable_get(:@after_destroy_callback_called)
@@ -133,12 +134,12 @@ class ParanoiaTest < test_framework
133
134
  model.remove_called_variables # clear called callback flags
134
135
  model.delete
135
136
 
136
- assert_equal nil, model.instance_variable_get(:@update_callback_called)
137
- assert_equal nil, model.instance_variable_get(:@save_callback_called)
138
- assert_equal nil, model.instance_variable_get(:@validate_called)
139
- assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
140
- assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called)
141
- assert_equal nil, model.instance_variable_get(:@after_commit_callback_called)
137
+ assert_nil model.instance_variable_get(:@update_callback_called)
138
+ assert_nil model.instance_variable_get(:@save_callback_called)
139
+ assert_nil model.instance_variable_get(:@validate_called)
140
+ assert_nil model.instance_variable_get(:@destroy_callback_called)
141
+ assert_nil model.instance_variable_get(:@after_destroy_callback_called)
142
+ assert_nil model.instance_variable_get(:@after_commit_callback_called)
142
143
  end
143
144
 
144
145
  def test_delete_in_transaction_behavior_for_plain_models_callbacks
@@ -149,11 +150,11 @@ class ParanoiaTest < test_framework
149
150
  model.delete
150
151
  end
151
152
 
152
- assert_equal nil, model.instance_variable_get(:@update_callback_called)
153
- assert_equal nil, model.instance_variable_get(:@save_callback_called)
154
- assert_equal nil, model.instance_variable_get(:@validate_called)
155
- assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
156
- assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called)
153
+ assert_nil model.instance_variable_get(:@update_callback_called)
154
+ assert_nil model.instance_variable_get(:@save_callback_called)
155
+ assert_nil model.instance_variable_get(:@validate_called)
156
+ assert_nil model.instance_variable_get(:@destroy_callback_called)
157
+ assert_nil model.instance_variable_get(:@after_destroy_callback_called)
157
158
  assert model.instance_variable_get(:@after_commit_callback_called)
158
159
  end
159
160
 
@@ -226,7 +227,7 @@ class ParanoiaTest < test_framework
226
227
  end
227
228
 
228
229
  def test_default_sentinel_value
229
- assert_equal nil, ParanoidModel.paranoia_sentinel_value
230
+ assert_nil ParanoidModel.paranoia_sentinel_value
230
231
  end
231
232
 
232
233
  def test_without_default_scope_option
@@ -375,7 +376,7 @@ class ParanoiaTest < test_framework
375
376
  model = CallbackModel.new
376
377
  model.save
377
378
  model.delete
378
- assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
379
+ assert_nil model.instance_variable_get(:@destroy_callback_called)
379
380
  end
380
381
 
381
382
  def test_destroy_behavior_for_callbacks
@@ -580,6 +581,38 @@ class ParanoiaTest < test_framework
580
581
  refute c.paranoia_destroyed?
581
582
  end
582
583
 
584
+ def test_restore_with_associations_using_recovery_window
585
+ parent = ParentModel.create
586
+ first_child = parent.very_related_models.create
587
+ second_child = parent.very_related_models.create
588
+
589
+ parent.destroy
590
+ second_child.update(deleted_at: parent.deleted_at + 11.minutes)
591
+
592
+ parent.restore!(:recursive => true)
593
+ assert_equal true, parent.deleted_at.nil?
594
+ assert_equal true, first_child.reload.deleted_at.nil?
595
+ assert_equal true, second_child.reload.deleted_at.nil?
596
+
597
+ parent.destroy
598
+ second_child.update(deleted_at: parent.deleted_at + 11.minutes)
599
+
600
+ parent.restore(:recursive => true, :recovery_window => 10.minutes)
601
+ assert_equal true, parent.deleted_at.nil?
602
+ assert_equal true, first_child.reload.deleted_at.nil?
603
+ assert_equal false, second_child.reload.deleted_at.nil?
604
+
605
+ second_child.restore
606
+ parent.destroy
607
+ first_child.update(deleted_at: parent.deleted_at - 11.minutes)
608
+ second_child.update(deleted_at: parent.deleted_at - 9.minutes)
609
+
610
+ ParentModel.restore(parent.id, :recursive => true, :recovery_window => 10.minutes)
611
+ assert_equal true, parent.reload.deleted_at.nil?
612
+ assert_equal false, first_child.reload.deleted_at.nil?
613
+ assert_equal true, second_child.reload.deleted_at.nil?
614
+ end
615
+
583
616
  def test_restore_with_associations
584
617
  parent = ParentModel.create
585
618
  first_child = parent.very_related_models.create
@@ -916,8 +949,8 @@ class ParanoiaTest < test_framework
916
949
  parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
917
950
  related_model = parent_model_with_counter_cache_column.related_models.create
918
951
 
919
- assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
920
- assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
952
+ assert_nil related_model.instance_variable_get(:@after_destroy_callback_called)
953
+ assert_nil related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
921
954
 
922
955
  related_model.destroy
923
956
 
@@ -932,6 +965,18 @@ class ParanoiaTest < test_framework
932
965
  related.valid?
933
966
  end
934
967
 
968
+ def test_assocation_not_soft_destroyed_validator
969
+ notParanoidModel = NotParanoidModelWithBelongsAndAssocationNotSoftDestroyedValidator.create
970
+ parentModel = ParentModel.create
971
+ assert notParanoidModel.valid?
972
+
973
+ notParanoidModel.parent_model = parentModel
974
+ assert notParanoidModel.valid?
975
+ parentModel.destroy
976
+ assert !notParanoidModel.valid?
977
+ assert notParanoidModel.errors.full_messages.include? "Parent model has been soft-deleted"
978
+ end
979
+
935
980
  # TODO: find a fix for Rails 4.1
936
981
  if ActiveRecord::VERSION::STRING !~ /\A4\.1/
937
982
  def test_counter_cache_column_update_on_really_destroy
@@ -950,14 +995,52 @@ class ParanoiaTest < test_framework
950
995
  parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
951
996
  related_model = parent_model_with_counter_cache_column.related_models.create
952
997
 
953
- assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
954
- assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
998
+ assert_nil related_model.instance_variable_get(:@after_destroy_callback_called)
999
+ assert_nil related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
955
1000
 
956
1001
  related_model.really_destroy!
957
1002
 
958
1003
  assert related_model.instance_variable_get(:@after_destroy_callback_called)
959
1004
  assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
960
1005
  end
1006
+
1007
+ def test_counter_cache_column_on_double_destroy
1008
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
1009
+ related_model = parent_model_with_counter_cache_column.related_models.create
1010
+
1011
+ related_model.destroy
1012
+ related_model.destroy
1013
+ assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
1014
+ end
1015
+
1016
+ def test_counter_cache_column_on_double_restore
1017
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
1018
+ related_model = parent_model_with_counter_cache_column.related_models.create
1019
+
1020
+ related_model.destroy
1021
+ related_model.restore
1022
+ related_model.restore
1023
+ assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
1024
+ end
1025
+
1026
+ def test_counter_cache_column_on_destroy_and_really_destroy
1027
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
1028
+ related_model = parent_model_with_counter_cache_column.related_models.create
1029
+
1030
+ related_model.destroy
1031
+ related_model.really_destroy!
1032
+ assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
1033
+ end
1034
+
1035
+ def test_counter_cache_column_on_restore
1036
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
1037
+ related_model = parent_model_with_counter_cache_column.related_models.create
1038
+
1039
+ related_model.destroy
1040
+ assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
1041
+ related_model.restore
1042
+ assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
1043
+ end
961
1044
  end
962
1045
 
963
1046
  private
@@ -1233,6 +1316,11 @@ class NotParanoidModelWithBelong < ActiveRecord::Base
1233
1316
  belongs_to :paranoid_model_with_has_one
1234
1317
  end
1235
1318
 
1319
+ class NotParanoidModelWithBelongsAndAssocationNotSoftDestroyedValidator < NotParanoidModelWithBelong
1320
+ belongs_to :parent_model
1321
+ validates :parent_model, association_not_soft_destroyed: true
1322
+ end
1323
+
1236
1324
  class FlaggedModel < PlainModel
1237
1325
  acts_as_paranoid :flag_column => :is_deleted
1238
1326
  end
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.1
4
+ version: 2.3.0
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: 2017-02-16 00:00:00.000000000 Z
11
+ date: 2017-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -76,6 +76,7 @@ files:
76
76
  - ".gitignore"
77
77
  - ".travis.yml"
78
78
  - CHANGELOG.md
79
+ - CODE_OF_CONDUCT.md
79
80
  - CONTRIBUTING.md
80
81
  - Gemfile
81
82
  - LICENSE
@@ -106,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
107
  version: 1.3.6
107
108
  requirements: []
108
109
  rubyforge_project:
109
- rubygems_version: 2.6.9
110
+ rubygems_version: 2.6.11
110
111
  signing_key:
111
112
  specification_version: 4
112
113
  summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, 4, and 5,