paranoia 2.1.3 → 2.1.4

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: 16d15104c160fe11573395f01bcf18d026d64291
4
- data.tar.gz: 009671430b1d508dc3a020773aa8a34666933b30
3
+ metadata.gz: 45933ae6db17d7ae34422587c41002a61915c588
4
+ data.tar.gz: 993a0cf0d2414179bcc916b3a3f00debf582332a
5
5
  SHA512:
6
- metadata.gz: 9d8cbcb3adc56426e31fdfdfe551c0e557ea023053358ce22083ef5a7140fa480ef004c6e363b95dfddd838f244090edf8cc6dc86a0cc05d98d00f6716d892a0
7
- data.tar.gz: c9a6eb1e4da8f21976b01152b0faed9ce736f9019896db44595475c75079266b3dccc6dc4f41a972ef1fba25003ebcb0b3ef76f29fb13884535b02ea5fa8fd69
6
+ metadata.gz: ef70ba0f7801c7f6cc624159120fd149a25d15e3ba8a06b050a1549bedb75bfc4bcf16c70c2882104ee7623294890c4760c2baae0f99ef2eb18dca8093c3a3f1
7
+ data.tar.gz: 452e9212c38168259988b8df9e26656cb3799cae8ab093341a9679b5d6b5430eae3430da82d67e4a46aa92cdefd92354dc61d126394e96f934b3bd6fb6119a92
@@ -0,0 +1,34 @@
1
+ Paranoia is an open source project and we encourage contributions.
2
+
3
+ ## Filing an issue
4
+
5
+ When filing an issue on the Paranoia project, please provide these details:
6
+
7
+ * A comprehensive list of steps to reproduce the issue.
8
+ * What you're *expecting* to happen compared with what's *actually* happening.
9
+ * Your application's complete `Gemfile.lock`, and `Gemfile.lock` as text in a [Gist](https://gist.github.com) (*not as an image*)
10
+ * Any relevant stack traces ("Full trace" preferred)
11
+
12
+ In 99% of cases, this information is enough to determine the cause and solution
13
+ to the problem that is being described.
14
+
15
+ Please remember to format code using triple backticks (\`) so that it is neatly
16
+ formatted when the issue is posted.
17
+
18
+ ## Pull requests
19
+
20
+ We gladly accept pull requests to add documentation, fix bugs and, in some circumstances,
21
+ add new features to Paranoia.
22
+
23
+ Here's a quick guide:
24
+
25
+ 1. Fork the repo.
26
+
27
+ 2. Run the tests. We only take pull requests with passing tests, and it's great
28
+ to know that you have a clean slate.
29
+
30
+ 3. Create new branch then make changes and add tests for your changes. Only
31
+ refactoring and documentation changes require no new tests. If you are adding
32
+ functionality or fixing a bug, we need tests!
33
+
34
+ 4. Push to your fork and submit a pull request.
data/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  Paranoia is a re-implementation of [acts\_as\_paranoid](http://github.com/technoweenie/acts_as_paranoid) for Rails 3 and Rails 4, using much, much, much less code.
4
4
 
5
- You would use either plugin / gem if you wished that when you called `destroy` on an Active Record object that it didn't actually destroy it, but just *hide* the record. Paranoia does this by setting a `deleted_at` field to the current time when you `destroy` a record, and hides it by scoping all queries on your model to only include records which do not have a `deleted_at` field.
5
+ When your app is using Paranoia, calling `destroy` on an ActiveRecord object doesn't actually destroy the database record, but just *hides* it. Paranoia does this by setting a `deleted_at` field to the current time when you `destroy` a record, and hides it by scoping all queries on your model to only include records which do not have a `deleted_at` field.
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
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.
10
10
 
11
11
  ## Getting Started Video
12
- Setup and basic usage of the paranoia gem
12
+ Setup and basic usage of the paranoia gem
13
13
  [GoRails #41](https://gorails.com/episodes/soft-delete-with-paranoia)
14
14
 
15
15
  ## Installation & Usage
@@ -94,22 +94,6 @@ If you really want it gone *gone*, call `really_destroy!`:
94
94
  # => client
95
95
  ```
96
96
 
97
- If you want a method to be called on destroy, simply provide a `before_destroy` callback:
98
-
99
- ``` ruby
100
- class Client < ActiveRecord::Base
101
- acts_as_paranoid
102
-
103
- before_destroy :some_method
104
-
105
- def some_method
106
- # do stuff
107
- end
108
-
109
- # ...
110
- end
111
- ```
112
-
113
97
  If you want to use a column other than `deleted_at`, you can pass it as an option:
114
98
 
115
99
  ``` ruby
@@ -180,12 +164,6 @@ Client.restore(id, :recursive => true)
180
164
  client.restore(:recursive => true)
181
165
  ```
182
166
 
183
- If you want callbacks to trigger before a restore:
184
-
185
- ``` ruby
186
- before_restore :callback_name_goes_here
187
- ```
188
-
189
167
  For more information, please look at the tests.
190
168
 
191
169
  #### About indexes:
@@ -207,6 +185,49 @@ add_index :clients, [:group_id, :other_id], where: "deleted_at IS NULL"
207
185
 
208
186
  Of course, this is not necessary for the indexes you always use in association with `with_deleted` or `only_deleted`.
209
187
 
188
+ ##### Unique Indexes
189
+
190
+ Becuse NULL != NULL in standard SQL, we can not simply create a unique index
191
+ on the deleted_at column and expect it to enforce that there only be one record
192
+ with a certain combination of values.
193
+
194
+ If your database supports them, good alternatives include partial indexes
195
+ (above) and indexes on computed columns. E.g.
196
+
197
+ ``` ruby
198
+ add_index :clients, [:group_id, 'COALESCE(deleted_at, false)'], unique: true
199
+ ```
200
+
201
+ If not, an alternative is to create a separate column which is maintained
202
+ alongside deleted_at for the sake of enforcing uniqueness. To that end,
203
+ paranoia makes use of two method to make its destroy and restore actions:
204
+ paranoia_restore_attributes and paranoia_destroy_attributes.
205
+
206
+ ``` ruby
207
+ add_column :clients, :active, :boolean
208
+ add_index :clients, [:group_id, :active], unique: true
209
+
210
+ class Client < ActiveRecord::Base
211
+ # optionally have paranoia make use of your unique column, so that
212
+ # your lookups will benefit from the unique index
213
+ acts_as_paranoid column: :active, sentinel_value: true
214
+
215
+ def paranoia_restore_attributes
216
+ {
217
+ deleted_at: nil,
218
+ active: true
219
+ }
220
+ end
221
+
222
+ def paranoia_destroy_attributes
223
+ {
224
+ deleted_at: current_time_from_proper_timezone,
225
+ active: nil
226
+ }
227
+ end
228
+ end
229
+ ```
230
+
210
231
  ## Acts As Paranoid Migration
211
232
 
212
233
  You can replace the older `acts_as_paranoid` methods as follows:
@@ -221,6 +242,24 @@ You can replace the older `acts_as_paranoid` methods as follows:
221
242
  The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's
222
243
  `restore` method does not do this.
223
244
 
245
+ ## Callbacks
246
+
247
+ Paranoia provides few callbacks. It triggers `destroy` callback when the record is marked as deleted and `real_destroy` when the record is completely removed from database. It also calls `restore` callback when record is restored via paranoia
248
+
249
+ For example if you want to index you records in some search engine you can do like this:
250
+
251
+ ```ruby
252
+ class Product < ActiveRecord::Base
253
+ acts_as_paranoid
254
+
255
+ after_destroy :update_document_in_search_engine
256
+ after_restore :update_document_in_search_engine
257
+ after_real_destroy :remove_document_from_search_engine
258
+ end
259
+ ```
260
+
261
+ You can use these events just like regular Rails callbacks with before, after and around hooks.
262
+
224
263
  ## License
225
264
 
226
265
  This gem is released under the MIT license.
@@ -22,14 +22,21 @@ module Paranoia
22
22
 
23
23
  def with_deleted
24
24
  if ActiveRecord::VERSION::STRING >= "4.1"
25
- unscope where: paranoia_column
26
- else
27
- all.tap { |x| x.default_scoped = false }
25
+ return unscope where: paranoia_column
28
26
  end
27
+ all.tap { |x| x.default_scoped = false }
29
28
  end
30
29
 
31
30
  def only_deleted
32
- with_deleted.where.not(paranoia_column => paranoia_sentinel_value)
31
+ if paranoia_sentinel_value.nil?
32
+ return with_deleted.where.not(paranoia_column => paranoia_sentinel_value)
33
+ end
34
+ # if paranoia_sentinel_value is not null, then it is possible that
35
+ # some deleted rows will hold a null value in the paranoia column
36
+ # these will not match != sentinel value because "NULL != value" is
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)
33
40
  end
34
41
  alias :deleted :only_deleted
35
42
 
@@ -47,18 +54,20 @@ module Paranoia
47
54
 
48
55
  module Callbacks
49
56
  def self.extended(klazz)
50
- klazz.define_callbacks :restore
57
+ [:restore, :real_destroy].each do |callback_name|
58
+ klazz.define_callbacks callback_name
51
59
 
52
- klazz.define_singleton_method("before_restore") do |*args, &block|
53
- set_callback(:restore, :before, *args, &block)
54
- end
60
+ klazz.define_singleton_method("before_#{callback_name}") do |*args, &block|
61
+ set_callback(callback_name, :before, *args, &block)
62
+ end
55
63
 
56
- klazz.define_singleton_method("around_restore") do |*args, &block|
57
- set_callback(:restore, :around, *args, &block)
58
- end
64
+ klazz.define_singleton_method("around_#{callback_name}") do |*args, &block|
65
+ set_callback(callback_name, :around, *args, &block)
66
+ end
59
67
 
60
- klazz.define_singleton_method("after_restore") do |*args, &block|
61
- set_callback(:restore, :after, *args, &block)
68
+ klazz.define_singleton_method("after_#{callback_name}") do |*args, &block|
69
+ set_callback(callback_name, :after, *args, &block)
70
+ end
62
71
  end
63
72
  end
64
73
  end
@@ -66,16 +75,13 @@ module Paranoia
66
75
  def destroy
67
76
  transaction do
68
77
  run_callbacks(:destroy) do
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
78
+ result = delete
79
+ next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
80
+ each_counter_cached_associations do |association|
81
+ foreign_key = association.reflection.foreign_key.to_sym
82
+ next if destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
83
+ next unless send(association.reflection.name)
84
+ association.decrement_counters
79
85
  end
80
86
  result
81
87
  end
@@ -83,7 +89,16 @@ module Paranoia
83
89
  end
84
90
 
85
91
  def delete
86
- touch_paranoia_column
92
+ raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
93
+ if persisted?
94
+ # if a transaction exists, add the record so that after_commit
95
+ # callbacks can be run
96
+ add_to_transaction
97
+ update_columns(paranoia_destroy_attributes)
98
+ elsif !frozen?
99
+ assign_attributes(paranoia_destroy_attributes)
100
+ end
101
+ self
87
102
  end
88
103
 
89
104
  def restore!(opts = {})
@@ -94,7 +109,7 @@ module Paranoia
94
109
  noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
95
110
  if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
96
111
  write_attribute paranoia_column, paranoia_sentinel_value
97
- update_column paranoia_column, paranoia_sentinel_value
112
+ update_columns(paranoia_restore_attributes)
98
113
  end
99
114
  restore_associated_records if opts[:recursive]
100
115
  end
@@ -111,16 +126,16 @@ module Paranoia
111
126
 
112
127
  private
113
128
 
114
- # touch paranoia column.
115
- # insert time to paranoia column.
116
- def touch_paranoia_column
117
- raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
118
- if persisted?
119
- touch(paranoia_column)
120
- elsif !frozen?
121
- write_attribute(paranoia_column, current_time_from_proper_timezone)
122
- end
123
- self
129
+ def paranoia_restore_attributes
130
+ {
131
+ paranoia_column => paranoia_sentinel_value
132
+ }
133
+ end
134
+
135
+ def paranoia_destroy_attributes
136
+ {
137
+ paranoia_column => current_time_from_proper_timezone
138
+ }
124
139
  end
125
140
 
126
141
  # restore associated records that have been soft deleted when
@@ -154,7 +169,7 @@ module Paranoia
154
169
  association_find_conditions = { association_foreign_key => self.id }
155
170
  end
156
171
 
157
- association_class = Object.const_get(association_class_name)
172
+ association_class = association_class_name.constantize
158
173
  if association_class.paranoid?
159
174
  association_class.only_deleted.where(association_find_conditions).first.try!(:restore, recursive: true)
160
175
  end
@@ -172,25 +187,27 @@ class ActiveRecord::Base
172
187
 
173
188
  alias :destroy_without_paranoia :destroy
174
189
  def really_destroy!
175
- dependent_reflections = self.class.reflections.select do |name, reflection|
176
- reflection.options[:dependent] == :destroy
177
- end
178
- if dependent_reflections.any?
179
- dependent_reflections.each do |name, reflection|
180
- association_data = self.send(name)
181
- # has_one association can return nil
182
- # .paranoid? will work for both instances and classes
183
- if association_data && association_data.paranoid?
184
- if reflection.collection?
185
- association_data.with_deleted.each(&:really_destroy!)
186
- else
190
+ transaction do
191
+ run_callbacks(:real_destroy) do
192
+ dependent_reflections = self.class.reflections.select do |name, reflection|
193
+ reflection.options[:dependent] == :destroy
194
+ end
195
+ if dependent_reflections.any?
196
+ dependent_reflections.each do |name, reflection|
197
+ association_data = self.send(name)
198
+ # has_one association can return nil
199
+ # .paranoid? will work for both instances and classes
200
+ next unless association_data && association_data.paranoid?
201
+ if reflection.collection?
202
+ next association_data.with_deleted.each(&:really_destroy!)
203
+ end
187
204
  association_data.really_destroy!
188
205
  end
189
206
  end
207
+ write_attribute(paranoia_column, current_time_from_proper_timezone)
208
+ destroy_without_paranoia
190
209
  end
191
210
  end
192
- write_attribute(paranoia_column, current_time_from_proper_timezone)
193
- destroy_without_paranoia
194
211
  end
195
212
 
196
213
  include Paranoia
@@ -237,3 +254,17 @@ class ActiveRecord::Base
237
254
  end
238
255
 
239
256
  require 'paranoia/rspec' if defined? RSpec
257
+
258
+ module ActiveRecord
259
+ module Validations
260
+ class UniquenessValidator < ActiveModel::EachValidator
261
+ protected
262
+ def build_relation_with_paranoia(klass, table, attribute, value)
263
+ relation = build_relation_without_paranoia(klass, table, attribute, value)
264
+ return relation unless klass.respond_to?(:paranoia_column)
265
+ relation.and(klass.arel_table[klass.paranoia_column].eq(klass.paranoia_sentinel_value))
266
+ end
267
+ alias_method_chain :build_relation, :paranoia
268
+ end
269
+ end
270
+ end
@@ -1,3 +1,3 @@
1
1
  module Paranoia
2
- VERSION = "2.1.3"
2
+ VERSION = "2.1.4"
3
3
  end
@@ -1,10 +1,10 @@
1
+ require 'bundler/setup'
1
2
  require 'active_record'
2
- ActiveRecord::Base.raise_in_transactional_callbacks = true if ActiveRecord::VERSION::STRING >= '4.2'
3
-
4
3
  require 'minitest/autorun'
5
- test_framework = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
4
+ require 'paranoia'
6
5
 
7
- require File.expand_path(File.dirname(__FILE__) + "/../lib/paranoia")
6
+ test_framework = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
7
+ ActiveRecord::Base.raise_in_transactional_callbacks = true if ActiveRecord::VERSION::STRING >= '4.2'
8
8
 
9
9
  def connect!
10
10
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', database: ':memory:'
@@ -28,7 +28,7 @@ def setup!
28
28
  'fail_callback_models' => 'deleted_at DATETIME',
29
29
  'related_models' => 'parent_model_id INTEGER, parent_model_with_counter_cache_column_id INTEGER, deleted_at DATETIME',
30
30
  'asplode_models' => 'parent_model_id INTEGER, deleted_at DATETIME',
31
- 'employers' => 'deleted_at DATETIME',
31
+ 'employers' => 'name VARCHAR(32), deleted_at DATETIME',
32
32
  'employees' => 'deleted_at DATETIME',
33
33
  'jobs' => 'employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME',
34
34
  'custom_column_models' => 'destroyed_at DATETIME',
@@ -37,6 +37,9 @@ def setup!
37
37
  'polymorphic_models' => 'parent_id INTEGER, parent_type STRING, deleted_at DATETIME',
38
38
  'namespaced_paranoid_has_ones' => 'deleted_at DATETIME, paranoid_belongs_tos_id INTEGER',
39
39
  'namespaced_paranoid_belongs_tos' => 'deleted_at DATETIME, paranoid_has_one_id INTEGER',
40
+ 'unparanoid_unique_models' => 'name VARCHAR(32), paranoid_with_unparanoids_id INTEGER',
41
+ 'active_column_models' => 'deleted_at DATETIME, active BOOLEAN',
42
+ 'active_column_model_with_uniqueness_validations' => 'name VARCHAR(32), deleted_at DATETIME, active BOOLEAN'
40
43
  }.each do |table_name, columns_as_sql_string|
41
44
  ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
42
45
  end
@@ -120,6 +123,22 @@ class ParanoiaTest < test_framework
120
123
  model.remove_called_variables # clear called callback flags
121
124
  model.delete
122
125
 
126
+ assert_equal nil, model.instance_variable_get(:@update_callback_called)
127
+ assert_equal nil, model.instance_variable_get(:@save_callback_called)
128
+ assert_equal nil, model.instance_variable_get(:@validate_called)
129
+ assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
130
+ assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called)
131
+ assert_equal nil, model.instance_variable_get(:@after_commit_callback_called)
132
+ end
133
+
134
+ def test_delete_in_transaction_behavior_for_plain_models_callbacks
135
+ model = CallbackModel.new
136
+ model.save
137
+ model.remove_called_variables # clear called callback flags
138
+ CallbackModel.transaction do
139
+ model.delete
140
+ end
141
+
123
142
  assert_equal nil, model.instance_variable_get(:@update_callback_called)
124
143
  assert_equal nil, model.instance_variable_get(:@save_callback_called)
125
144
  assert_equal nil, model.instance_variable_get(:@validate_called)
@@ -184,6 +203,38 @@ class ParanoiaTest < test_framework
184
203
  assert_equal nil, ParanoidModel.paranoia_sentinel_value
185
204
  end
186
205
 
206
+ def test_active_column_model
207
+ model = ActiveColumnModel.new
208
+ assert_equal 0, model.class.count
209
+ model.save!
210
+ assert_nil model.deleted_at
211
+ assert_equal true, model.active
212
+ assert_equal 1, model.class.count
213
+ model.destroy
214
+
215
+ assert_equal false, model.deleted_at.nil?
216
+ assert_nil model.active
217
+ assert model.paranoia_destroyed?
218
+
219
+ assert_equal 0, model.class.count
220
+ assert_equal 1, model.class.unscoped.count
221
+ assert_equal 1, model.class.only_deleted.count
222
+ assert_equal 1, model.class.deleted.count
223
+ end
224
+
225
+ def test_active_column_model_with_uniqueness_validation_only_checks_non_deleted_records
226
+ a = ActiveColumnModelWithUniquenessValidation.create!(name: "A")
227
+ a.destroy
228
+ b = ActiveColumnModelWithUniquenessValidation.new(name: "A")
229
+ assert b.valid?
230
+ end
231
+
232
+ def test_active_column_model_with_uniqueness_validation_still_works_on_non_deleted_records
233
+ a = ActiveColumnModelWithUniquenessValidation.create!(name: "A")
234
+ b = ActiveColumnModelWithUniquenessValidation.new(name: "A")
235
+ refute b.valid?
236
+ end
237
+
187
238
  def test_sentinel_value_for_custom_sentinel_models
188
239
  model = CustomSentinelModel.new
189
240
  assert_equal 0, model.class.count
@@ -453,6 +504,14 @@ class ParanoiaTest < test_framework
453
504
  assert RelatedModel.unscoped.exists?(child_2.id)
454
505
  end
455
506
 
507
+ def test_really_destroy_behavior_for_callbacks
508
+ model = CallbackModel.new
509
+ model.save
510
+ model.really_destroy!
511
+
512
+ assert model.instance_variable_get(:@real_destroy_callback_called)
513
+ end
514
+
456
515
  def test_really_delete
457
516
  model = ParanoidModel.new
458
517
  model.save
@@ -685,6 +744,19 @@ class ParanoiaTest < test_framework
685
744
  # essentially, we're just ensuring that this doesn't crash
686
745
  end
687
746
 
747
+ def test_validates_uniqueness_only_checks_non_deleted_records
748
+ a = Employer.create!(name: "A")
749
+ a.destroy
750
+ b = Employer.new(name: "A")
751
+ assert b.valid?
752
+ end
753
+
754
+ def test_validates_uniqueness_still_works_on_non_deleted_records
755
+ a = Employer.create!(name: "A")
756
+ b = Employer.new(name: "A")
757
+ refute b.valid?
758
+ end
759
+
688
760
  def test_i_am_the_destroyer
689
761
  expected = %Q{
690
762
  Sharon: "There should be a method called I_AM_THE_DESTROYER!"
@@ -800,6 +872,13 @@ class ParanoiaTest < test_framework
800
872
  # assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called)
801
873
  end
802
874
 
875
+ def test_uniqueness_for_unparanoid_associated
876
+ parent_model = ParanoidWithUnparanoids.create
877
+ related = parent_model.unparanoid_unique_models.create
878
+ # will raise exception if model is not checked for paranoia
879
+ related.valid?
880
+ end
881
+
803
882
  # TODO: find a fix for Rails 4.1
804
883
  if ActiveRecord::VERSION::STRING !~ /\A4\.1/
805
884
  def test_counter_cache_column_update_on_really_destroy
@@ -841,6 +920,16 @@ class ParanoidModel < ActiveRecord::Base
841
920
  acts_as_paranoid
842
921
  end
843
922
 
923
+ class ParanoidWithUnparanoids < ActiveRecord::Base
924
+ self.table_name = 'plain_models'
925
+ has_many :unparanoid_unique_models
926
+ end
927
+
928
+ class UnparanoidUniqueModel < ActiveRecord::Base
929
+ belongs_to :paranoid_with_unparanoids
930
+ validates :name, :uniqueness => true
931
+ end
932
+
844
933
  class FailCallbackModel < ActiveRecord::Base
845
934
  belongs_to :parent_model
846
935
  acts_as_paranoid
@@ -853,20 +942,25 @@ class FeaturefulModel < ActiveRecord::Base
853
942
  validates :name, :presence => true, :uniqueness => true
854
943
  end
855
944
 
945
+ class NonParanoidChildModel < ActiveRecord::Base
946
+ validates :name, :presence => true, :uniqueness => true
947
+ end
948
+
856
949
  class PlainModel < ActiveRecord::Base
857
950
  end
858
951
 
859
952
  class CallbackModel < ActiveRecord::Base
860
953
  acts_as_paranoid
861
- before_destroy {|model| model.instance_variable_set :@destroy_callback_called, true }
862
- before_restore {|model| model.instance_variable_set :@restore_callback_called, true }
863
- before_update {|model| model.instance_variable_set :@update_callback_called, true }
864
- before_save {|model| model.instance_variable_set :@save_callback_called, true}
954
+ before_destroy { |model| model.instance_variable_set :@destroy_callback_called, true }
955
+ before_restore { |model| model.instance_variable_set :@restore_callback_called, true }
956
+ before_update { |model| model.instance_variable_set :@update_callback_called, true }
957
+ before_save { |model| model.instance_variable_set :@save_callback_called, true}
958
+ before_real_destroy { |model| model.instance_variable_set :@real_destroy_callback_called, true }
865
959
 
866
- after_destroy {|model| model.instance_variable_set :@after_destroy_callback_called, true }
867
- after_commit {|model| model.instance_variable_set :@after_commit_callback_called, true }
960
+ after_destroy { |model| model.instance_variable_set :@after_destroy_callback_called, true }
961
+ after_commit { |model| model.instance_variable_set :@after_commit_callback_called, true }
868
962
 
869
- validate {|model| model.instance_variable_set :@validate_called, true }
963
+ validate { |model| model.instance_variable_set :@validate_called, true }
870
964
 
871
965
  def remove_called_variables
872
966
  instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil}
@@ -909,6 +1003,7 @@ end
909
1003
 
910
1004
  class Employer < ActiveRecord::Base
911
1005
  acts_as_paranoid
1006
+ validates_uniqueness_of :name
912
1007
  has_many :jobs
913
1008
  has_many :employees, :through => :jobs
914
1009
  end
@@ -933,6 +1028,43 @@ class CustomSentinelModel < ActiveRecord::Base
933
1028
  acts_as_paranoid sentinel_value: DateTime.new(0)
934
1029
  end
935
1030
 
1031
+ class ActiveColumnModel < ActiveRecord::Base
1032
+ acts_as_paranoid column: :active, sentinel_value: true
1033
+
1034
+ def paranoia_restore_attributes
1035
+ {
1036
+ deleted_at: nil,
1037
+ active: true
1038
+ }
1039
+ end
1040
+
1041
+ def paranoia_destroy_attributes
1042
+ {
1043
+ deleted_at: current_time_from_proper_timezone,
1044
+ active: nil
1045
+ }
1046
+ end
1047
+ end
1048
+
1049
+ class ActiveColumnModelWithUniquenessValidation < ActiveRecord::Base
1050
+ validates :name, :uniqueness => true
1051
+ acts_as_paranoid column: :active, sentinel_value: true
1052
+
1053
+ def paranoia_restore_attributes
1054
+ {
1055
+ deleted_at: nil,
1056
+ active: true
1057
+ }
1058
+ end
1059
+
1060
+ def paranoia_destroy_attributes
1061
+ {
1062
+ deleted_at: current_time_from_proper_timezone,
1063
+ active: nil
1064
+ }
1065
+ end
1066
+ end
1067
+
936
1068
  class NonParanoidModel < ActiveRecord::Base
937
1069
  end
938
1070
 
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.3
4
+ version: 2.1.4
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-06-17 00:00:00.000000000 Z
11
+ date: 2015-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -66,6 +66,7 @@ files:
66
66
  - ".gitignore"
67
67
  - ".travis.yml"
68
68
  - CHANGELOG.md
69
+ - CONTRIBUTING.md
69
70
  - Gemfile
70
71
  - LICENSE
71
72
  - README.md
@@ -94,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
95
  version: 1.3.6
95
96
  requirements: []
96
97
  rubyforge_project: paranoia
97
- rubygems_version: 2.4.8
98
+ rubygems_version: 2.4.5.1
98
99
  signing_key:
99
100
  specification_version: 4
100
101
  summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much,