paranoia 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +11 -0
- data/Gemfile +14 -1
- data/README.md +81 -3
- data/lib/paranoia.rb +90 -13
- data/lib/paranoia/version.rb +1 -1
- data/paranoia.gemspec +1 -2
- data/test/paranoia_test.rb +170 -20
- metadata +14 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fe3ef85f4b72d9f860b21f59bcf8f0416b6462f
|
4
|
+
data.tar.gz: a60d2f35334726d1d2af0fc45c03fe0a8fbe8653
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9c966fc4c04b1ce8bc50bdaf988f7d16290cece9913dcd49cfe738d8751f692450f4daf57e7fe0289c6575dad031317756462326232efb5418a03d427560642
|
7
|
+
data.tar.gz: 76b091060495418ac3ccf2163a226b8ce43f6ec2e078e75a55e16c566bd968715a9a2694f3b4358e51e308a2be17f674ab9f50fc205c2e75e7e2d04b23ddef59
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,4 +1,17 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'sqlite3', :platforms => [:ruby]
|
4
|
+
gem 'activerecord-jdbcsqlite3-adapter', :platforms => [:jruby]
|
5
|
+
|
6
|
+
platforms :rbx do
|
7
|
+
gem 'rubysl', '~> 2.0'
|
8
|
+
gem 'rubysl-test-unit'
|
9
|
+
gem 'rubinius-developer_tools'
|
10
|
+
end
|
11
|
+
|
12
|
+
rails = ENV['RAILS'] || '~> 4.0.2'
|
13
|
+
|
14
|
+
gem 'rails', rails
|
2
15
|
|
3
16
|
# Specify your gem's dependencies in paranoia.gemspec
|
4
17
|
gemspec
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Paranoia is a re-implementation of [acts\_as\_paranoid](http://github.com/techno
|
|
4
4
|
|
5
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 "hid" 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.
|
6
6
|
|
7
|
-
If you wish to actually destroy an object you may call
|
7
|
+
If you wish to actually destroy an object you may call `really_destroy!`.
|
8
8
|
|
9
9
|
## Installation & Usage
|
10
10
|
|
@@ -66,9 +66,23 @@ class Client < ActiveRecord::Base
|
|
66
66
|
end
|
67
67
|
```
|
68
68
|
|
69
|
-
Hey presto, it's there!
|
69
|
+
Hey presto, it's there! Calling `destroy` will now set the `deleted_at` column:
|
70
70
|
|
71
|
-
|
71
|
+
|
72
|
+
```
|
73
|
+
>> client.deleted_at => nil
|
74
|
+
>> client.destroy => client
|
75
|
+
>> client.deleted_at => [current timestamp]
|
76
|
+
```
|
77
|
+
|
78
|
+
If you really want it gone *gone*, call `really_destroy!`
|
79
|
+
|
80
|
+
```
|
81
|
+
>> client.deleted_at => nil
|
82
|
+
>> client.real_destroy! => client
|
83
|
+
```
|
84
|
+
|
85
|
+
If you want a method to be called on destroy, simply provide a `before_destroy` callback:
|
72
86
|
|
73
87
|
```ruby
|
74
88
|
class Client < ActiveRecord::Base
|
@@ -84,6 +98,70 @@ class Client < ActiveRecord::Base
|
|
84
98
|
end
|
85
99
|
```
|
86
100
|
|
101
|
+
If you want to use a column other than `deleted_at`, you can pass it as an option:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class Client < ActiveRecord::Base
|
105
|
+
acts_as_paranoid column: :destroyed_at
|
106
|
+
|
107
|
+
...
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
If you want to access soft-deleted associations, override the getter method:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
def product
|
115
|
+
Product.unscoped { super }
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
If you want to find all records, even those which are deleted:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
Client.with_deleted
|
123
|
+
```
|
124
|
+
|
125
|
+
If you want to find only the deleted records:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Client.only_deleted
|
129
|
+
```
|
130
|
+
|
131
|
+
If you want to check if a record is soft-deleted:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
client.destroyed?
|
135
|
+
```
|
136
|
+
|
137
|
+
If you want to restore a record:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
Client.restore(id)
|
141
|
+
```
|
142
|
+
|
143
|
+
If you want to restore a whole bunch of records:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
Client.restore([id1, id2, ..., idN])
|
147
|
+
```
|
148
|
+
|
149
|
+
If you want to restore a record and their dependently destroyed associated records:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
Client.restore(id, :recursive => true)
|
153
|
+
```
|
154
|
+
|
155
|
+
If you want callbacks to trigger before a restore:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
before_restore :callback_name_goes_here
|
159
|
+
```
|
160
|
+
|
161
|
+
For more information, please look at the tests.
|
162
|
+
|
163
|
+
## Acts As Paranoid Migration
|
164
|
+
|
87
165
|
You can replace the older acts_as_paranoid methods as follows:
|
88
166
|
|
89
167
|
| Old Syntax | New Syntax |
|
data/lib/paranoia.rb
CHANGED
@@ -8,19 +8,23 @@ module Paranoia
|
|
8
8
|
def paranoid? ; true ; end
|
9
9
|
|
10
10
|
def with_deleted
|
11
|
-
|
11
|
+
if ActiveRecord::VERSION::STRING >= "4.1"
|
12
|
+
unscope where: paranoia_column
|
13
|
+
else
|
14
|
+
all.tap { |x| x.default_scoped = false }
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
def only_deleted
|
15
|
-
with_deleted.where.not(
|
19
|
+
with_deleted.where.not(paranoia_column => nil)
|
16
20
|
end
|
17
21
|
alias :deleted :only_deleted
|
18
22
|
|
19
|
-
def restore(id)
|
23
|
+
def restore(id, opts = {})
|
20
24
|
if id.is_a?(Array)
|
21
|
-
id.map { |one_id| restore(one_id) }
|
25
|
+
id.map { |one_id| restore(one_id, opts) }
|
22
26
|
else
|
23
|
-
only_deleted.find(id).restore!
|
27
|
+
only_deleted.find(id).restore!(opts)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -44,30 +48,97 @@ module Paranoia
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def destroy
|
47
|
-
run_callbacks(:destroy) {
|
51
|
+
run_callbacks(:destroy) { touch_paranoia_column(true) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# As of Rails 4.1.0 +destroy!+ will no longer remove the record from the db
|
55
|
+
# unless you touch the paranoia column before.
|
56
|
+
# We need to override it here otherwise children records might be removed
|
57
|
+
# when they shouldn't
|
58
|
+
if ActiveRecord::VERSION::STRING >= "4.1"
|
59
|
+
def destroy!
|
60
|
+
destroyed? ? super : destroy || raise(ActiveRecord::RecordNotDestroyed)
|
61
|
+
end
|
48
62
|
end
|
49
63
|
|
50
64
|
def delete
|
51
65
|
return if new_record?
|
52
|
-
|
66
|
+
touch_paranoia_column(false)
|
53
67
|
end
|
54
68
|
|
55
|
-
def restore!
|
56
|
-
|
69
|
+
def restore!(opts = {})
|
70
|
+
ActiveRecord::Base.transaction do
|
71
|
+
run_callbacks(:restore) do
|
72
|
+
update_column paranoia_column, nil
|
73
|
+
restore_associated_records if opts[:recursive]
|
74
|
+
end
|
75
|
+
end
|
57
76
|
end
|
77
|
+
alias :restore :restore!
|
58
78
|
|
59
79
|
def destroyed?
|
60
|
-
!!
|
80
|
+
!!send(paranoia_column)
|
61
81
|
end
|
62
82
|
alias :deleted? :destroyed?
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# touch paranoia column.
|
87
|
+
# insert time to paranoia column.
|
88
|
+
# @param with_transaction [Boolean] exec with ActiveRecord Transactions.
|
89
|
+
def touch_paranoia_column(with_transaction=false)
|
90
|
+
if with_transaction
|
91
|
+
with_transaction_returning_status { touch(paranoia_column) }
|
92
|
+
else
|
93
|
+
touch(paranoia_column)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# restore associated records that have been soft deleted when
|
98
|
+
# we called #destroy
|
99
|
+
def restore_associated_records
|
100
|
+
destroyed_associations = self.class.reflect_on_all_associations.select do |association|
|
101
|
+
association.options[:dependent] == :destroy
|
102
|
+
end
|
103
|
+
|
104
|
+
destroyed_associations.each do |association|
|
105
|
+
association = send(association.name)
|
106
|
+
|
107
|
+
if association.paranoid?
|
108
|
+
association.only_deleted.each { |record| record.restore(:recursive => true) }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
63
112
|
end
|
64
113
|
|
65
114
|
class ActiveRecord::Base
|
66
|
-
def self.acts_as_paranoid
|
115
|
+
def self.acts_as_paranoid(options={})
|
116
|
+
alias :really_destroy! :destroy
|
67
117
|
alias :destroy! :destroy
|
68
|
-
alias :delete!
|
118
|
+
alias :delete! :delete
|
69
119
|
include Paranoia
|
70
|
-
|
120
|
+
class_attribute :paranoia_column
|
121
|
+
|
122
|
+
self.paranoia_column = options[:column] || :deleted_at
|
123
|
+
default_scope { where(paranoia_column => nil) }
|
124
|
+
|
125
|
+
before_restore {
|
126
|
+
self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers)
|
127
|
+
}
|
128
|
+
after_restore {
|
129
|
+
self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers)
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
# Please do not use this method in production.
|
134
|
+
# Pretty please.
|
135
|
+
def self.I_AM_THE_DESTROYER!
|
136
|
+
# TODO: actually implement spelling error fixes
|
137
|
+
puts %Q{
|
138
|
+
Sharon: "There should be a method called I_AM_THE_DESTROYER!"
|
139
|
+
Ryan: "What should this method do?"
|
140
|
+
Sharon: "It should fix all the spelling errors on the page!"
|
141
|
+
}
|
71
142
|
end
|
72
143
|
|
73
144
|
def self.paranoid? ; false ; end
|
@@ -79,4 +150,10 @@ class ActiveRecord::Base
|
|
79
150
|
def persisted?
|
80
151
|
paranoid? ? !new_record? : super
|
81
152
|
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def paranoia_column
|
157
|
+
self.class.paranoia_column
|
158
|
+
end
|
82
159
|
end
|
data/lib/paranoia/version.rb
CHANGED
data/paranoia.gemspec
CHANGED
@@ -17,8 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.add_dependency "activerecord", "~> 4.0"
|
18
18
|
|
19
19
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
20
|
-
s.add_development_dependency "
|
21
|
-
s.add_development_dependency "rake", "0.8.7"
|
20
|
+
s.add_development_dependency "rake"
|
22
21
|
|
23
22
|
s.files = `git ls-files`.split("\n")
|
24
23
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
data/test/paranoia_test.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
require 'test/unit'
|
2
1
|
require 'active_record'
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + "/../lib/paranoia")
|
4
|
-
|
5
|
-
DB_FILE = 'tmp/test_db'
|
6
2
|
|
7
|
-
|
8
|
-
|
3
|
+
test_framework = if ActiveRecord::VERSION::STRING >= "4.1"
|
4
|
+
require 'minitest/autorun'
|
5
|
+
MiniTest::Test
|
6
|
+
else
|
7
|
+
require 'test/unit'
|
8
|
+
Test::Unit::TestCase
|
9
|
+
end
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/paranoia")
|
9
11
|
|
10
|
-
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :
|
12
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', database: ':memory:'
|
11
13
|
ActiveRecord::Base.connection.execute 'CREATE TABLE parent_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
12
14
|
ActiveRecord::Base.connection.execute 'CREATE TABLE paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER, deleted_at DATETIME)'
|
13
15
|
ActiveRecord::Base.connection.execute 'CREATE TABLE featureful_models (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME, name VARCHAR(32))'
|
@@ -17,8 +19,16 @@ ActiveRecord::Base.connection.execute 'CREATE TABLE related_models (id INTEGER N
|
|
17
19
|
ActiveRecord::Base.connection.execute 'CREATE TABLE employers (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
18
20
|
ActiveRecord::Base.connection.execute 'CREATE TABLE employees (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)'
|
19
21
|
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)'
|
22
|
+
ActiveRecord::Base.connection.execute 'CREATE TABLE custom_column_models (id INTEGER NOT NULL PRIMARY KEY, destroyed_at DATETIME)'
|
23
|
+
ActiveRecord::Base.connection.execute 'CREATE TABLE non_paranoid_models (id INTEGER NOT NULL PRIMARY KEY, parent_model_id INTEGER)'
|
24
|
+
|
25
|
+
class ParanoiaTest < test_framework
|
26
|
+
def setup
|
27
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
28
|
+
ActiveRecord::Base.connection.execute "DELETE FROM #{table}"
|
29
|
+
end
|
30
|
+
end
|
20
31
|
|
21
|
-
class ParanoiaTest < Test::Unit::TestCase
|
22
32
|
def test_plain_model_class_is_not_paranoid
|
23
33
|
assert_equal false, PlainModel.paranoid?
|
24
34
|
end
|
@@ -42,7 +52,7 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
42
52
|
|
43
53
|
model.destroy
|
44
54
|
|
45
|
-
|
55
|
+
assert model.to_param
|
46
56
|
assert_equal to_param, model.to_param
|
47
57
|
end
|
48
58
|
|
@@ -59,6 +69,37 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
59
69
|
assert_equal 0, model.class.unscoped.count
|
60
70
|
end
|
61
71
|
|
72
|
+
# Anti-regression test for #81, which would've introduced a bug to break this test.
|
73
|
+
def test_destroy_behavior_for_plain_models_callbacks
|
74
|
+
model = CallbackModel.new
|
75
|
+
model.save
|
76
|
+
model.remove_called_variables # clear called callback flags
|
77
|
+
model.destroy
|
78
|
+
|
79
|
+
assert_equal nil, model.instance_variable_get(:@update_callback_called)
|
80
|
+
assert_equal nil, model.instance_variable_get(:@save_callback_called)
|
81
|
+
assert_equal nil, model.instance_variable_get(:@validate_called)
|
82
|
+
|
83
|
+
assert model.instance_variable_get(:@destroy_callback_called)
|
84
|
+
assert model.instance_variable_get(:@after_destroy_callback_called)
|
85
|
+
assert model.instance_variable_get(:@after_commit_callback_called)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def test_delete_behavior_for_plain_models_callbacks
|
90
|
+
model = CallbackModel.new
|
91
|
+
model.save
|
92
|
+
model.remove_called_variables # clear called callback flags
|
93
|
+
model.delete
|
94
|
+
|
95
|
+
assert_equal nil, model.instance_variable_get(:@update_callback_called)
|
96
|
+
assert_equal nil, model.instance_variable_get(:@save_callback_called)
|
97
|
+
assert_equal nil, model.instance_variable_get(:@validate_called)
|
98
|
+
assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
|
99
|
+
assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called)
|
100
|
+
assert_equal nil, model.instance_variable_get(:@after_commit_callback_called)
|
101
|
+
end
|
102
|
+
|
62
103
|
def test_destroy_behavior_for_paranoid_models
|
63
104
|
model = ParanoidModel.new
|
64
105
|
assert_equal 0, model.class.count
|
@@ -73,7 +114,6 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
73
114
|
end
|
74
115
|
|
75
116
|
def test_scoping_behavior_for_paranoid_models
|
76
|
-
ParanoidModel.unscoped.delete_all
|
77
117
|
parent1 = ParentModel.create
|
78
118
|
parent2 = ParentModel.create
|
79
119
|
p1 = ParanoidModel.create(:parent_model => parent1)
|
@@ -88,6 +128,23 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
88
128
|
assert_equal [p1,p3], parent1.paranoid_models.with_deleted
|
89
129
|
end
|
90
130
|
|
131
|
+
def test_destroy_behavior_for_custom_column_models
|
132
|
+
model = CustomColumnModel.new
|
133
|
+
assert_equal 0, model.class.count
|
134
|
+
model.save!
|
135
|
+
assert_nil model.destroyed_at
|
136
|
+
assert_equal 1, model.class.count
|
137
|
+
model.destroy
|
138
|
+
|
139
|
+
assert_equal false, model.destroyed_at.nil?
|
140
|
+
assert model.destroyed?
|
141
|
+
|
142
|
+
assert_equal 0, model.class.count
|
143
|
+
assert_equal 1, model.class.unscoped.count
|
144
|
+
assert_equal 1, model.class.only_deleted.count
|
145
|
+
assert_equal 1, model.class.deleted.count
|
146
|
+
end
|
147
|
+
|
91
148
|
def test_destroy_behavior_for_featureful_paranoid_models
|
92
149
|
model = get_featureful_model
|
93
150
|
assert_equal 0, model.class.count
|
@@ -164,14 +221,14 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
164
221
|
model = CallbackModel.new
|
165
222
|
model.save
|
166
223
|
model.delete
|
167
|
-
assert_equal nil, model.instance_variable_get(:@
|
224
|
+
assert_equal nil, model.instance_variable_get(:@destroy_callback_called)
|
168
225
|
end
|
169
226
|
|
170
227
|
def test_destroy_behavior_for_callbacks
|
171
228
|
model = CallbackModel.new
|
172
229
|
model.save
|
173
230
|
model.destroy
|
174
|
-
assert model.instance_variable_get(:@
|
231
|
+
assert model.instance_variable_get(:@destroy_callback_called)
|
175
232
|
end
|
176
233
|
|
177
234
|
def test_restore
|
@@ -189,13 +246,14 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
189
246
|
assert_equal false, model.destroyed?
|
190
247
|
end
|
191
248
|
|
249
|
+
# Regression test for #92
|
192
250
|
def test_destroy_twice
|
193
251
|
model = ParanoidModel.new
|
194
252
|
model.save
|
195
253
|
model.destroy
|
196
254
|
model.destroy
|
197
255
|
|
198
|
-
assert_equal
|
256
|
+
assert_equal 1, ParanoidModel.unscoped.where(id: model.id).count
|
199
257
|
end
|
200
258
|
|
201
259
|
def test_restore_behavior_for_callbacks
|
@@ -216,11 +274,19 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
216
274
|
def test_real_destroy
|
217
275
|
model = ParanoidModel.new
|
218
276
|
model.save
|
219
|
-
model.
|
220
|
-
|
277
|
+
model.really_destroy!
|
221
278
|
refute ParanoidModel.unscoped.exists?(model.id)
|
222
279
|
end
|
223
280
|
|
281
|
+
if ActiveRecord::VERSION::STRING < "4.1"
|
282
|
+
def test_real_destroy
|
283
|
+
model = ParanoidModel.new
|
284
|
+
model.save
|
285
|
+
model.destroy!
|
286
|
+
refute ParanoidModel.unscoped.exists?(model.id)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
224
290
|
def test_real_delete
|
225
291
|
model = ParanoidModel.new
|
226
292
|
model.save
|
@@ -256,6 +322,59 @@ class ParanoiaTest < Test::Unit::TestCase
|
|
256
322
|
refute c.destroyed?
|
257
323
|
end
|
258
324
|
|
325
|
+
def test_restore_with_associations
|
326
|
+
parent = ParentModel.create
|
327
|
+
first_child = parent.very_related_models.create
|
328
|
+
second_child = parent.non_paranoid_models.create
|
329
|
+
|
330
|
+
parent.destroy
|
331
|
+
assert_equal false, parent.deleted_at.nil?
|
332
|
+
assert_equal false, first_child.reload.deleted_at.nil?
|
333
|
+
assert_equal true, second_child.destroyed?
|
334
|
+
|
335
|
+
parent.restore!
|
336
|
+
assert_equal true, parent.deleted_at.nil?
|
337
|
+
assert_equal false, first_child.reload.deleted_at.nil?
|
338
|
+
assert_equal true, second_child.destroyed?
|
339
|
+
|
340
|
+
parent.destroy
|
341
|
+
parent.restore(:recursive => true)
|
342
|
+
assert_equal true, parent.deleted_at.nil?
|
343
|
+
assert_equal true, first_child.reload.deleted_at.nil?
|
344
|
+
assert_equal true, second_child.destroyed?
|
345
|
+
|
346
|
+
parent.destroy
|
347
|
+
ParentModel.restore(parent.id, :recursive => true)
|
348
|
+
assert_equal true, parent.reload.deleted_at.nil?
|
349
|
+
assert_equal true, first_child.reload.deleted_at.nil?
|
350
|
+
assert_equal true, second_child.destroyed?
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_observers_notified
|
354
|
+
a = ParanoidModelWithObservers.create
|
355
|
+
a.destroy
|
356
|
+
a.restore!
|
357
|
+
|
358
|
+
assert a.observers_notified.select {|args| args == [:before_restore, a]}
|
359
|
+
assert a.observers_notified.select {|args| args == [:after_restore, a]}
|
360
|
+
end
|
361
|
+
|
362
|
+
def test_observers_not_notified_if_not_supported
|
363
|
+
a = ParanoidModelWithObservers.create
|
364
|
+
a.destroy
|
365
|
+
a.restore!
|
366
|
+
# essentially, we're just ensuring that this doesn't crash
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_i_am_the_destroyer
|
370
|
+
output = capture(:stdout) { ParanoidModel.I_AM_THE_DESTROYER! }
|
371
|
+
assert_equal %Q{
|
372
|
+
Sharon: "There should be a method called I_AM_THE_DESTROYER!"
|
373
|
+
Ryan: "What should this method do?"
|
374
|
+
Sharon: "It should fix all the spelling errors on the page!"
|
375
|
+
}, output
|
376
|
+
end
|
377
|
+
|
259
378
|
private
|
260
379
|
def get_featureful_model
|
261
380
|
FeaturefulModel.new(:name => "not empty")
|
@@ -264,10 +383,6 @@ end
|
|
264
383
|
|
265
384
|
# Helper classes
|
266
385
|
|
267
|
-
class ParentModel < ActiveRecord::Base
|
268
|
-
has_many :paranoid_models
|
269
|
-
end
|
270
|
-
|
271
386
|
class ParanoidModel < ActiveRecord::Base
|
272
387
|
belongs_to :parent_model
|
273
388
|
acts_as_paranoid
|
@@ -283,13 +398,27 @@ end
|
|
283
398
|
|
284
399
|
class CallbackModel < ActiveRecord::Base
|
285
400
|
acts_as_paranoid
|
286
|
-
before_destroy {|model| model.instance_variable_set :@
|
401
|
+
before_destroy {|model| model.instance_variable_set :@destroy_callback_called, true }
|
287
402
|
before_restore {|model| model.instance_variable_set :@restore_callback_called, true }
|
403
|
+
before_update {|model| model.instance_variable_set :@update_callback_called, true }
|
404
|
+
before_save {|model| model.instance_variable_set :@save_callback_called, true}
|
405
|
+
|
406
|
+
after_destroy {|model| model.instance_variable_set :@after_destroy_callback_called, true }
|
407
|
+
after_commit {|model| model.instance_variable_set :@after_commit_callback_called, true }
|
408
|
+
|
409
|
+
validate {|model| model.instance_variable_set :@validate_called, true }
|
410
|
+
|
411
|
+
def remove_called_variables
|
412
|
+
instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil}
|
413
|
+
end
|
288
414
|
end
|
289
415
|
|
290
416
|
class ParentModel < ActiveRecord::Base
|
291
417
|
acts_as_paranoid
|
418
|
+
has_many :paranoid_models
|
292
419
|
has_many :related_models
|
420
|
+
has_many :very_related_models, :class_name => 'RelatedModel', dependent: :destroy
|
421
|
+
has_many :non_paranoid_models, dependent: :destroy
|
293
422
|
end
|
294
423
|
|
295
424
|
class RelatedModel < ActiveRecord::Base
|
@@ -314,3 +443,24 @@ class Job < ActiveRecord::Base
|
|
314
443
|
belongs_to :employer
|
315
444
|
belongs_to :employee
|
316
445
|
end
|
446
|
+
|
447
|
+
class CustomColumnModel < ActiveRecord::Base
|
448
|
+
acts_as_paranoid column: :destroyed_at
|
449
|
+
end
|
450
|
+
|
451
|
+
class NonParanoidModel < ActiveRecord::Base
|
452
|
+
end
|
453
|
+
|
454
|
+
class ParanoidModelWithObservers < ParanoidModel
|
455
|
+
def observers_notified
|
456
|
+
@observers_notified ||= []
|
457
|
+
end
|
458
|
+
|
459
|
+
def self.notify_observer(*args)
|
460
|
+
observers_notified << args
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
class ParanoidModelWithoutObservers < ParanoidModel
|
465
|
+
self.class.send(remove_method :notify_observers) if method_defined?(:notify_observers)
|
466
|
+
end
|
metadata
CHANGED
@@ -1,71 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paranoia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
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:
|
11
|
+
date: 2014-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 0.8.7
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.8.7
|
69
55
|
description: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using
|
70
56
|
much, much, much less code. You would use either plugin / gem if you wished that
|
71
57
|
when you called destroy on an Active Record object that it didn't actually destroy
|
@@ -77,7 +63,8 @@ executables: []
|
|
77
63
|
extensions: []
|
78
64
|
extra_rdoc_files: []
|
79
65
|
files:
|
80
|
-
- .gitignore
|
66
|
+
- ".gitignore"
|
67
|
+
- ".travis.yml"
|
81
68
|
- Gemfile
|
82
69
|
- LICENSE
|
83
70
|
- README.md
|
@@ -95,17 +82,17 @@ require_paths:
|
|
95
82
|
- lib
|
96
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
84
|
requirements:
|
98
|
-
- -
|
85
|
+
- - ">="
|
99
86
|
- !ruby/object:Gem::Version
|
100
87
|
version: '0'
|
101
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
89
|
requirements:
|
103
|
-
- -
|
90
|
+
- - ">="
|
104
91
|
- !ruby/object:Gem::Version
|
105
92
|
version: 1.3.6
|
106
93
|
requirements: []
|
107
94
|
rubyforge_project: paranoia
|
108
|
-
rubygems_version: 2.
|
95
|
+
rubygems_version: 2.2.0
|
109
96
|
signing_key:
|
110
97
|
specification_version: 4
|
111
98
|
summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much,
|