paranoia 2.0.1 → 2.0.2
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 +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,
|