paranoia 2.1.3 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,