paranoia 2.1.0 → 2.1.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: f0cb57d2b73781793a6c745fb89bb9d7793fecb3
4
- data.tar.gz: f53171d8795a238508541336bbf6e0aa6082959e
3
+ metadata.gz: eb9d6ab15bd6fb2e445d1cbb7d83d93c920f94f0
4
+ data.tar.gz: d48bc9001fcdbb023d9312c1706dcba6f602c07d
5
5
  SHA512:
6
- metadata.gz: 42eab22150eb1e35f7c49b430949905ddf7590695ab6cb8df7cadbd0012ad4038375f859ba63cc200f0b3fe2bde8a0941aeaf51a9daca4a0803ad5d7a3a4841d
7
- data.tar.gz: f88c66a92dd499958c14b2c1c4443334522c524270eaab270166ad702db7fa1ae47c4f927a79795fa57f157d8dc7a628f4fce9025e2606e3583dc3b7430c0ba5
6
+ metadata.gz: 2609ec5884f55c9d466a69a7d8df51ed380706c54ec47feab1be36666b63c617f4c1abb133e77f2f05552d23df4182170b0d6934938aacadbf9511214a447a39
7
+ data.tar.gz: 74b632024df0628881ac8ed4d338ac301470ff4a0ce985425055aed32537d0315c2c095b4c8f92ebb5467cc9f750f5ab878e06b1092e71c4582cdd82d17ad7a7
data/README.md CHANGED
@@ -25,7 +25,7 @@ gem "paranoia", "~> 2.0"
25
25
  Of course you can install this from GitHub as well:
26
26
 
27
27
  ``` ruby
28
- gem "paranoia", :github => "radar/paranoia", :branch => "master"
28
+ gem "paranoia", :github => "radar/paranoia", :branch => "rails3"
29
29
  # or
30
30
  gem "paranoia", :github => "radar/paranoia", :branch => "rails4"
31
31
  ```
@@ -124,6 +124,16 @@ def product
124
124
  end
125
125
  ```
126
126
 
127
+ If you want to include associated soft-deleted objects, you can (un)scope the association:
128
+
129
+ ``` ruby
130
+ class Person < ActiveRecord::Base
131
+ belongs_to :group, -> { with_deleted }
132
+ end
133
+
134
+ Person.includes(:group).all
135
+ ```
136
+
127
137
  If you want to find all records, even those which are deleted:
128
138
 
129
139
  ``` ruby
@@ -184,27 +194,6 @@ You can replace the older `acts_as_paranoid` methods as follows:
184
194
  The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's
185
195
  `restore` method does not do this.
186
196
 
187
- ## Support for Unique Keys with Null Values
188
-
189
- Most databases ignore null columns when it comes to resolving unique index
190
- constraints. This means unique constraints that involve nullable columns may be
191
- problematic. Instead of using `NULL` to represent a not-deleted row, you can pick
192
- a value that you want paranoia to mean not deleted. Note that you can/should
193
- now apply a `NOT NULL` constraint to your `deleted_at` column.
194
-
195
- Per model:
196
-
197
- ```ruby
198
- # pick some value
199
- acts_as_paranoid sentinel_value: DateTime.new(0)
200
- ```
201
-
202
- or globally in a rails initializer, e.g. `config/initializer/paranoia.rb`
203
-
204
- ```ruby
205
- Paranoia.default_sentinel_value = DateTime.new(0)
206
- ```
207
-
208
197
  ## License
209
198
 
210
199
  This gem is released under the MIT license.
@@ -33,8 +33,15 @@ module Paranoia
33
33
  end
34
34
  alias :deleted :only_deleted
35
35
 
36
- def restore(id, opts = {})
37
- Array(id).flatten.map { |one_id| only_deleted.find(one_id).restore!(opts) }
36
+ def restore(id_or_ids, opts = {})
37
+ ids = Array(id_or_ids).flatten
38
+ any_object_instead_of_id = ids.any? { |id| ActiveRecord::Base === id }
39
+ if any_object_instead_of_id
40
+ ids.map! { |id| ActiveRecord::Base === id ? id.id : id }
41
+ ActiveSupport::Deprecation.warn("You are passing an instance of ActiveRecord::Base to `restore`. " \
42
+ "Please pass the id of the object by calling `.id`")
43
+ end
44
+ ids.map { |id| only_deleted.find(id).restore!(opts) }
38
45
  end
39
46
  end
40
47
 
@@ -59,7 +66,18 @@ module Paranoia
59
66
  def destroy
60
67
  transaction do
61
68
  run_callbacks(:destroy) do
62
- touch_paranoia_column
69
+ result = touch_paranoia_column
70
+ if result && ActiveRecord::VERSION::STRING >= '4.2'
71
+ each_counter_cached_associations do |association|
72
+ foreign_key = association.reflection.foreign_key.to_sym
73
+ unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
74
+ if send(association.reflection.name)
75
+ association.decrement_counters
76
+ end
77
+ end
78
+ end
79
+ end
80
+ result
63
81
  end
64
82
  end
65
83
  end
@@ -95,8 +113,7 @@ module Paranoia
95
113
 
96
114
  # touch paranoia column.
97
115
  # insert time to paranoia column.
98
- # @param with_transaction [Boolean] exec with ActiveRecord Transactions.
99
- def touch_paranoia_column(with_transaction=false)
116
+ def touch_paranoia_column
100
117
  raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
101
118
  if persisted?
102
119
  touch(paranoia_column)
@@ -1,3 +1,3 @@
1
1
  module Paranoia
2
- VERSION = "2.1.0"
2
+ VERSION = "2.1.1"
3
3
  end
@@ -12,27 +12,32 @@ end
12
12
 
13
13
  def setup!
14
14
  connect!
15
- ActiveRecord::Base.connection.execute 'CREATE TABLE parent_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
16
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
17
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER)'
18
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_build_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_and_build_id INTEGER, name VARCHAR(32))'
19
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_anthor_class_name_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER)'
20
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_foreign_key_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER)'
21
- ActiveRecord::Base.connection.execute 'CREATE TABLE not_paranoid_model_with_belongs (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER)'
22
- ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_model_with_has_one_and_builds (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, color VARCHAR(32), deleted_at DATETIME, has_one_foreign_key_id INTEGER)'
23
- ActiveRecord::Base.connection.execute 'CREATE TABLE featureful_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME, name VARCHAR(32))'
24
- ActiveRecord::Base.connection.execute 'CREATE TABLE plain_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
25
- ActiveRecord::Base.connection.execute 'CREATE TABLE callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
26
- ActiveRecord::Base.connection.execute 'CREATE TABLE fail_callback_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
27
- ActiveRecord::Base.connection.execute 'CREATE TABLE related_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER NOT NULL, deleted_at DATETIME)'
28
- ActiveRecord::Base.connection.execute 'CREATE TABLE asplode_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
29
- ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
30
- ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
31
- ActiveRecord::Base.connection.execute 'CREATE TABLE jobs (id INTEGER NOT NULL PRIMARY KEY, employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME)'
32
- ActiveRecord::Base.connection.execute 'CREATE TABLE custom_column_models (id INTEGER NOT NULL PRIMARY KEY, destroyed_at DATETIME)'
33
- ActiveRecord::Base.connection.execute 'CREATE TABLE custom_sentinel_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME NOT NULL)'
34
- ActiveRecord::Base.connection.execute 'CREATE TABLE non_paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER)'
35
- ActiveRecord::Base.connection.execute 'CREATE TABLE polymorphic_models (id INTEGER NOT NULL PRIMARY KEY, parent_id INTEGER, parent_type STRING, deleted_at DATETIME)'
15
+ {
16
+ 'parent_model_with_counter_cache_columns' => 'related_models_count INTEGER DEFAULT 0',
17
+ 'parent_models' => 'deleted_at DATETIME',
18
+ 'paranoid_models' => 'parent_model_id INTEGER, deleted_at DATETIME',
19
+ 'paranoid_model_with_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER',
20
+ 'paranoid_model_with_build_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_and_build_id INTEGER, name VARCHAR(32)',
21
+ 'paranoid_model_with_anthor_class_name_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER',
22
+ 'paranoid_model_with_foreign_key_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER',
23
+ 'not_paranoid_model_with_belongs' => 'parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER',
24
+ 'paranoid_model_with_has_one_and_builds' => 'parent_model_id INTEGER, color VARCHAR(32), deleted_at DATETIME, has_one_foreign_key_id INTEGER',
25
+ 'featureful_models' => 'deleted_at DATETIME, name VARCHAR(32)',
26
+ 'plain_models' => 'deleted_at DATETIME',
27
+ 'callback_models' => 'deleted_at DATETIME',
28
+ 'fail_callback_models' => 'deleted_at DATETIME',
29
+ 'related_models' => 'parent_model_id INTEGER, parent_model_with_counter_cache_column_id INTEGER, deleted_at DATETIME',
30
+ 'asplode_models' => 'parent_model_id INTEGER, deleted_at DATETIME',
31
+ 'employers' => 'deleted_at DATETIME',
32
+ 'employees' => 'deleted_at DATETIME',
33
+ 'jobs' => 'employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME',
34
+ 'custom_column_models' => 'destroyed_at DATETIME',
35
+ 'custom_sentinel_models' => 'deleted_at DATETIME NOT NULL',
36
+ 'non_paranoid_models' => 'parent_model_id INTEGER',
37
+ 'polymorphic_models' => 'parent_id INTEGER, parent_type STRING, deleted_at DATETIME'
38
+ }.each do |table_name, columns_as_sql_string|
39
+ ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
40
+ end
36
41
  end
37
42
 
38
43
  class WithDifferentConnection < ActiveRecord::Base
@@ -758,6 +763,56 @@ class ParanoiaTest < test_framework
758
763
  assert_equal 0, polymorphic.class.count
759
764
  end
760
765
 
766
+ def test_counter_cache_column_update_on_destroy#_and_restore_and_really_destroy
767
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
768
+ related_model = parent_model_with_counter_cache_column.related_models.create
769
+
770
+ assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
771
+ related_model.destroy
772
+ assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
773
+ end
774
+
775
+ def test_callbacks_for_counter_cache_column_update_on_destroy
776
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
777
+ related_model = parent_model_with_counter_cache_column.related_models.create
778
+
779
+ assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
780
+ assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
781
+
782
+ related_model.destroy
783
+
784
+ assert related_model.instance_variable_get(:@after_destroy_callback_called)
785
+ # assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
786
+ end
787
+
788
+ # TODO: find a fix for Rails 4.1
789
+ if ActiveRecord::VERSION::STRING !~ /\A4\.1/
790
+ def test_counter_cache_column_update_on_really_destroy
791
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
792
+ related_model = parent_model_with_counter_cache_column.related_models.create
793
+
794
+ assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count
795
+ related_model.really_destroy!
796
+ assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count
797
+ end
798
+ end
799
+
800
+ # TODO: find a fix for Rails 4.0 and 4.1
801
+ if ActiveRecord::VERSION::STRING >= '4.2'
802
+ def test_callbacks_for_counter_cache_column_update_on_really_destroy!
803
+ parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create
804
+ related_model = parent_model_with_counter_cache_column.related_models.create
805
+
806
+ assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called)
807
+ assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
808
+
809
+ related_model.really_destroy!
810
+
811
+ assert related_model.instance_variable_get(:@after_destroy_callback_called)
812
+ assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
813
+ end
814
+ end
815
+
761
816
  private
762
817
  def get_featureful_model
763
818
  FeaturefulModel.new(:name => "not empty")
@@ -814,9 +869,27 @@ class ParentModel < ActiveRecord::Base
814
869
  has_one :polymorphic_model, as: :parent, dependent: :destroy
815
870
  end
816
871
 
872
+ class ParentModelWithCounterCacheColumn < ActiveRecord::Base
873
+ has_many :related_models
874
+ end
875
+
817
876
  class RelatedModel < ActiveRecord::Base
818
877
  acts_as_paranoid
819
878
  belongs_to :parent_model
879
+ belongs_to :parent_model_with_counter_cache_column, counter_cache: true
880
+
881
+ after_destroy do |model|
882
+ if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0
883
+ model.instance_variable_set :@after_destroy_callback_called, true
884
+ end
885
+ end
886
+ after_commit :set_after_commit_on_destroy_callback_called, on: :destroy
887
+
888
+ def set_after_commit_on_destroy_callback_called
889
+ if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0
890
+ self.instance_variable_set :@after_commit_on_destroy_callback_called, true
891
+ end
892
+ end
820
893
  end
821
894
 
822
895
  class Employer < ActiveRecord::Base
@@ -914,8 +987,6 @@ class FlaggedModelWithCustomIndex < PlainModel
914
987
  acts_as_paranoid :flag_column => :is_deleted, :indexed_column => :is_deleted
915
988
  end
916
989
 
917
-
918
-
919
990
  class AsplodeModel < ActiveRecord::Base
920
991
  acts_as_paranoid
921
992
  before_destroy do |r|
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.1.0
4
+ version: 2.1.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: 2015-01-24 00:00:00.000000000 Z
11
+ date: 2015-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  version: 1.3.6
95
95
  requirements: []
96
96
  rubyforge_project: paranoia
97
- rubygems_version: 2.2.2
97
+ rubygems_version: 2.4.6
98
98
  signing_key:
99
99
  specification_version: 4
100
100
  summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much,