delete_paranoid 0.0.2 → 0.0.3
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.
- data/lib/delete_paranoid/version.rb +1 -1
- data/lib/delete_paranoid.rb +22 -4
- data/test/database_setup.rb +6 -1
- data/test/helper.rb +125 -0
- data/test/test_delete_paranoid.rb +65 -40
- metadata +4 -4
data/lib/delete_paranoid.rb
CHANGED
@@ -4,29 +4,47 @@ module DeleteParanoid
|
|
4
4
|
module ActiveRecordExtensions
|
5
5
|
def acts_as_paranoid
|
6
6
|
class << self
|
7
|
-
alias_method :
|
7
|
+
alias_method :delete_all!, :delete_all
|
8
8
|
end
|
9
|
+
alias_method :destroy!, :destroy
|
9
10
|
default_scope where(:deleted_at => nil)
|
10
|
-
include DeleteParanoid::InstanceMethods
|
11
11
|
extend DeleteParanoid::ClassMethods
|
12
|
+
include DeleteParanoid::InstanceMethods
|
12
13
|
end
|
13
14
|
end
|
15
|
+
|
14
16
|
module ClassMethods
|
15
|
-
def with_deleted
|
17
|
+
def with_deleted
|
16
18
|
self.unscoped do
|
17
19
|
yield
|
18
20
|
end
|
19
21
|
end
|
22
|
+
|
23
|
+
def delete_all(conditions = nil)
|
24
|
+
update_all ["deleted_at = ?", Time.now.utc], conditions
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy_all!(conditions = nil)
|
28
|
+
if conditions
|
29
|
+
where(conditions).destroy_all!
|
30
|
+
else
|
31
|
+
to_a.each {|object| object.destroy! }.tap { reset }
|
32
|
+
end
|
33
|
+
end
|
20
34
|
end
|
35
|
+
|
21
36
|
module InstanceMethods
|
22
37
|
def destroy
|
23
38
|
if persisted?
|
24
39
|
with_transaction_returning_status do
|
25
40
|
_run_destroy_callbacks do
|
26
|
-
|
41
|
+
self.deleted_at = Time.now.utc
|
42
|
+
self.class.delete_all :id => self.id
|
27
43
|
@destroyed = true
|
28
44
|
end
|
29
45
|
end
|
46
|
+
else
|
47
|
+
@destroyed = true
|
30
48
|
end
|
31
49
|
|
32
50
|
freeze
|
data/test/database_setup.rb
CHANGED
@@ -3,11 +3,16 @@ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
|
3
3
|
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
4
4
|
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
|
5
5
|
|
6
|
-
ActiveRecord::Schema.define(:version =>
|
6
|
+
ActiveRecord::Schema.define(:version => 2) do
|
7
7
|
create_table :blogs, :force => true do |t|
|
8
8
|
t.column :title, :string
|
9
9
|
t.column :body, :string
|
10
10
|
t.column :deleted_at, :timestamp
|
11
11
|
end
|
12
|
+
create_table :comments, :force => true do |t|
|
13
|
+
t.column :blog_id, :integer
|
14
|
+
t.column :text, :string
|
15
|
+
t.column :deleted_at, :timestamp
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
data/test/helper.rb
CHANGED
@@ -18,5 +18,130 @@ require 'delete_paranoid'
|
|
18
18
|
require 'database_setup'
|
19
19
|
|
20
20
|
class Test::Unit::TestCase
|
21
|
+
|
22
|
+
def self.should_soft_destroy(subject)
|
23
|
+
should "assign deleted_at on #{subject}" do
|
24
|
+
assert_not_nil instance_variable_get(:"@#{subject}").deleted_at
|
25
|
+
end
|
26
|
+
should "set #{subject} to destroyed" do
|
27
|
+
assert instance_variable_get(:"@#{subject}").destroyed?
|
28
|
+
end
|
29
|
+
should "freeze #{subject}" do
|
30
|
+
assert instance_variable_get(:"@#{subject}").frozen?
|
31
|
+
end
|
32
|
+
should "not be found normally" do
|
33
|
+
destroyed_subject = instance_variable_get(:"@#{subject}")
|
34
|
+
assert_raises ActiveRecord::RecordNotFound do
|
35
|
+
destroyed_subject.class.find destroyed_subject.id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
should "be found when in with_deleted block" do
|
39
|
+
destroyed_subject = instance_variable_get(:"@#{subject}")
|
40
|
+
destroyed_subject.class.with_deleted do
|
41
|
+
assert_nothing_raised ActiveRecord::RecordNotFound do
|
42
|
+
destroyed_subject.class.find destroyed_subject.id
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.should_hard_destroy(subject)
|
49
|
+
should "not be retrievable" do
|
50
|
+
destroyed_subject = instance_variable_get(:"@#{subject}")
|
51
|
+
assert_raises ActiveRecord::RecordNotFound do
|
52
|
+
destroyed_subject.class.find destroyed_subject.id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
should "not be retrievable in with_deleted block" do
|
56
|
+
destroyed_subject = instance_variable_get(:"@#{subject}")
|
57
|
+
destroyed_subject.class.with_deleted do
|
58
|
+
assert_raises ActiveRecord::RecordNotFound do
|
59
|
+
destroyed_subject.class.find destroyed_subject.id
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.should_trigger_destroy_callbacks(subject)
|
66
|
+
should "call before_destroy callbacks on #{subject}" do
|
67
|
+
assert instance_variable_get(:"@#{subject}").called_before_destroy
|
68
|
+
end
|
69
|
+
should "call after_destroy callbacks on #{subject}" do
|
70
|
+
assert instance_variable_get(:"@#{subject}").called_after_destroy
|
71
|
+
end
|
72
|
+
should "call after_commit_on_destroy callbacks on #{subject}" do
|
73
|
+
assert instance_variable_get(:"@#{subject}").called_after_commit_on_destroy
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.should_not_trigger_update_callbacks(subject)
|
78
|
+
should "not call before_update callbacks on #{subject}" do
|
79
|
+
assert !instance_variable_get(:"@#{subject}").called_before_update
|
80
|
+
end
|
81
|
+
should "not call after_update callbacks on #{subject}" do
|
82
|
+
assert !instance_variable_get(:"@#{subject}").called_after_update
|
83
|
+
end
|
84
|
+
should "not call after_commit_on_update callbacks on #{subject}" do
|
85
|
+
assert !instance_variable_get(:"@#{subject}").called_after_commit_on_update
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
21
89
|
end
|
22
90
|
|
91
|
+
|
92
|
+
module CallbackTester
|
93
|
+
ATTRS = %w{ called_before_destroy called_after_destroy called_after_commit_on_destroy called_before_update called_after_update called_after_commit_on_update }
|
94
|
+
|
95
|
+
def self.included(base)
|
96
|
+
base.class_eval do
|
97
|
+
attr_accessor *ATTRS
|
98
|
+
|
99
|
+
before_update :call_me_before_update
|
100
|
+
after_update :call_me_after_update
|
101
|
+
|
102
|
+
before_destroy :call_me_before_destroy
|
103
|
+
after_destroy :call_me_after_destroy
|
104
|
+
|
105
|
+
after_commit :call_me_after_commit_on_destroy, :on => :destroy
|
106
|
+
after_commit :call_me_after_commit_on_update, :on => :update
|
107
|
+
|
108
|
+
alias_method_chain :initialize, :callback_init
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def initialize_with_callback_init(*args)
|
113
|
+
reset_callback_flags!
|
114
|
+
initialize_without_callback_init(*args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def reset_callback_flags!
|
118
|
+
ATTRS.each do |attr|
|
119
|
+
send("#{attr}=", false)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def call_me_before_destroy
|
124
|
+
@called_before_destroy = true
|
125
|
+
end
|
126
|
+
|
127
|
+
def call_me_after_destroy
|
128
|
+
@called_after_destroy = true
|
129
|
+
end
|
130
|
+
|
131
|
+
def call_me_after_commit_on_destroy
|
132
|
+
@called_after_commit_on_destroy = true
|
133
|
+
end
|
134
|
+
|
135
|
+
def call_me_before_update
|
136
|
+
@called_before_update = true
|
137
|
+
end
|
138
|
+
|
139
|
+
def call_me_after_update
|
140
|
+
@called_after_update = true
|
141
|
+
end
|
142
|
+
|
143
|
+
def call_me_after_commit_on_update
|
144
|
+
@called_after_commit_on_update = true
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -2,62 +2,87 @@ require File.join(File.dirname(__FILE__), 'helper')
|
|
2
2
|
|
3
3
|
class TestDeleteParanoid < Test::Unit::TestCase
|
4
4
|
class Blog < ActiveRecord::Base
|
5
|
+
has_many :comments, :dependent => :destroy
|
5
6
|
acts_as_paranoid
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
before_destroy :call_me_before_destroy
|
10
|
-
after_destroy :call_me_after_destroy
|
11
|
-
|
12
|
-
after_commit :call_me_after_commit_on_destroy, :on => :destroy
|
13
|
-
|
14
|
-
def initialize(*attrs)
|
15
|
-
@called_before_destroy = @called_after_destroy = @called_after_commit_on_destroy = false
|
16
|
-
super(*attrs)
|
17
|
-
end
|
18
|
-
|
19
|
-
def call_me_before_destroy
|
20
|
-
@called_before_destroy = true
|
21
|
-
end
|
7
|
+
attr_accessible :title
|
8
|
+
include CallbackTester
|
9
|
+
end
|
22
10
|
|
23
|
-
|
24
|
-
|
11
|
+
class Comment < ActiveRecord::Base
|
12
|
+
acts_as_paranoid
|
13
|
+
attr_accessible :text
|
14
|
+
include CallbackTester
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with paranoid instance' do
|
18
|
+
setup do
|
19
|
+
@blog = Blog.new
|
25
20
|
end
|
26
|
-
|
27
|
-
|
28
|
-
@called_after_commit_on_destroy = true
|
21
|
+
should 'have destroy! method' do
|
22
|
+
assert @blog.respond_to? :destroy!
|
29
23
|
end
|
30
24
|
end
|
31
|
-
|
32
25
|
context 'with paranoid class' do
|
33
|
-
should 'have
|
34
|
-
assert Blog.respond_to? :
|
26
|
+
should 'have delete_all! method' do
|
27
|
+
assert Blog.respond_to? :delete_all!
|
35
28
|
end
|
29
|
+
|
36
30
|
context 'when on instance destroyed softly' do
|
37
31
|
setup do
|
38
32
|
@blog = Blog.create! :title => 'foo'
|
39
33
|
@blog.destroy
|
40
34
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
35
|
+
|
36
|
+
should_soft_destroy :blog
|
37
|
+
should_trigger_destroy_callbacks :blog
|
38
|
+
should_not_trigger_update_callbacks :blog
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when an instance with dependents is destroyed softly' do
|
42
|
+
setup do
|
43
|
+
@comment = Comment.create! :text => 'bar'
|
44
|
+
@blog = Blog.create!(:title => 'foo').tap do |blog|
|
45
|
+
blog.comments << @comment
|
47
46
|
end
|
47
|
+
@blog.destroy
|
48
48
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
assert @blog.called_after_destroy
|
54
|
-
end
|
55
|
-
should "call after_commit_on_destroy callbacks" do
|
56
|
-
assert @blog.called_after_commit_on_destroy
|
57
|
-
end
|
49
|
+
|
50
|
+
should_soft_destroy :blog
|
51
|
+
should_trigger_destroy_callbacks :blog
|
52
|
+
should_not_trigger_update_callbacks :blog
|
58
53
|
|
54
|
+
should_soft_destroy :comment
|
55
|
+
should_trigger_destroy_callbacks :comment
|
56
|
+
# should_not_trigger_update_callbacks :comment
|
59
57
|
end
|
58
|
+
|
59
|
+
context "when on instance destroyed hardly" do
|
60
|
+
setup do
|
61
|
+
@blog = Blog.create! :title => 'foo'
|
62
|
+
@blog.destroy!
|
63
|
+
end
|
60
64
|
|
61
|
-
|
65
|
+
should_hard_destroy :blog
|
66
|
+
should_trigger_destroy_callbacks :blog
|
67
|
+
should_not_trigger_update_callbacks :blog
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when an instance with dependents is destroyed hardly' do
|
71
|
+
setup do
|
72
|
+
@comment = Comment.create! :text => 'bar'
|
73
|
+
@blog = Blog.create!(:title => 'foo').tap do |blog|
|
74
|
+
blog.comments << @comment
|
75
|
+
end
|
76
|
+
@blog.destroy!
|
77
|
+
end
|
78
|
+
|
79
|
+
should_hard_destroy :blog
|
80
|
+
should_trigger_destroy_callbacks :blog
|
81
|
+
should_not_trigger_update_callbacks :blog
|
82
|
+
# should_hard_destroy :comment
|
83
|
+
should_trigger_destroy_callbacks :comment
|
84
|
+
# should_not_trigger_update_callbacks :comment
|
85
|
+
end
|
86
|
+
|
62
87
|
end
|
63
88
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delete_paranoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Sonnek
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-04 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|