immortal 1.0.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +0 -11
- data/LICENSE +9 -0
- data/README.md +12 -0
- data/immortal.gemspec +18 -12
- data/lib/immortal.rb +44 -34
- data/lib/immortal/belongs_to.rb +2 -2
- data/lib/immortal/singular_association.rb +10 -6
- data/spec/immortal_spec.rb +67 -45
- data/spec/spec_helper.rb +34 -18
- metadata +68 -27
- data/Gemfile.lock +0 -43
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 60ac9bd43b41aa290750329470ab9cd76e8adcb3
|
4
|
+
data.tar.gz: a779e1fb76253a4148f62e186c347be7ed19c847
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 34bddc9c389145c501948b6255821a30424cd126fca8e6367a1ee65f7d99d32ea96fe53c684575d3c0c184f9c962fca802c1786e351e6b65d4ce858669ad70cf
|
7
|
+
data.tar.gz: a34d764cdc236d6cb6f055c32bdeb2eab35448390171af5988eaa0accca696e2a843d87f683cd65a9f753624b97168fb1569e5d4994c8ddfd4e85fb9bdda9db2
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -2,14 +2,3 @@ source "http://rubygems.org"
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in immortal.gemspec
|
4
4
|
gemspec
|
5
|
-
|
6
|
-
group :test, :development do
|
7
|
-
|
8
|
-
# gem "ruby-debug", "~> 0.10.4", :require => "ruby-debug", :platform => :ruby_18
|
9
|
-
|
10
|
-
# gem "ruby-debug19", :require => "ruby-debug", :platform => :ruby_19
|
11
|
-
# # Uncomment this and rebundle to use the debugger under 1.9.3
|
12
|
-
# TODO: Remove this when ruby-debug-base19-0.11.26 is published
|
13
|
-
# gem "ruby-debug-base19", "0.11.26", :platform => :ruby_19
|
14
|
-
|
15
|
-
end
|
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) Teambox
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -57,3 +57,15 @@ If you want to improve immortal
|
|
57
57
|
- 0.1.3 fix bug where join model is not immortal
|
58
58
|
- 0.1.2 fix loading issue when the `deleted` column doesn't exist (or even the table)
|
59
59
|
- 0.1.1 fix behavior with `has_many :through` associations
|
60
|
+
|
61
|
+
## License
|
62
|
+
|
63
|
+
(The MIT License)
|
64
|
+
|
65
|
+
Copyright (c) Teambox
|
66
|
+
|
67
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
68
|
+
|
69
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
70
|
+
|
71
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/immortal.gemspec
CHANGED
@@ -1,22 +1,28 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
|
-
s.name =
|
6
|
-
s.version = '
|
7
|
-
s.authors = [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
s.
|
5
|
+
s.name = 'immortal'
|
6
|
+
s.version = '2.0.0'
|
7
|
+
s.authors = [
|
8
|
+
'Jordi Romero', 'Saimon Moore', 'Pau Ramon', 'Carlos Saura', 'Andres Bravo',
|
9
|
+
'Fran Casas', 'Pau Perez'
|
10
|
+
]
|
11
|
+
s.email = ['jordi@jrom.net', 'saimon@saimonmoore.net']
|
12
|
+
s.homepage = 'http://github.com/teambox/immortal'
|
13
|
+
s.summary = 'Replacement for acts_as_paranoid for Rails 4'
|
14
|
+
s.description = 'Typical paranoid gem built for Rails 4 and with the ' \
|
15
|
+
"minimum code needed to satisfy acts_as_paranoid's API"
|
16
|
+
s.license = 'MIT'
|
12
17
|
|
13
18
|
s.files = `git ls-files`.split("\n")
|
14
19
|
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
15
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
-
s.require_paths = [
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
21
|
+
s.require_paths = ['lib']
|
17
22
|
|
18
|
-
s.add_dependency 'activerecord', '~>
|
23
|
+
s.add_dependency 'activerecord', '~> 4.0.0'
|
19
24
|
s.add_development_dependency 'rspec', '~> 2.6.0'
|
20
25
|
s.add_development_dependency 'sqlite3'
|
21
|
-
|
26
|
+
s.add_development_dependency 'byebug'
|
27
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
22
28
|
end
|
data/lib/immortal.rb
CHANGED
@@ -8,19 +8,6 @@ module Immortal
|
|
8
8
|
base.send :include, BelongsTo
|
9
9
|
base.class_eval do
|
10
10
|
class << self
|
11
|
-
|
12
|
-
# In has_many :through => join_model we have to explicitly add
|
13
|
-
# the 'not deleted' scope, otherwise it will take all the rows
|
14
|
-
# from the join model
|
15
|
-
def has_many_mortal(association_id, options = {}, &extension)
|
16
|
-
has_many_immortal(association_id, options, &extension).tap do
|
17
|
-
# FIXME This must be re-implemented after the ActiveRecord internals refactor in 3.1
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
alias_method :has_many_immortal, :has_many
|
22
|
-
alias_method :has_many, :has_many_mortal
|
23
|
-
|
24
11
|
alias :mortal_delete_all :delete_all
|
25
12
|
alias :delete_all :immortal_delete_all
|
26
13
|
end
|
@@ -37,26 +24,20 @@ module Immortal
|
|
37
24
|
new_scope = self.unscoped
|
38
25
|
our_scope = self.current_scope || self.unscoped
|
39
26
|
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
non_immortal_constraints_sql = non_immortal_constraints.to_a.map do |constraint|
|
45
|
-
constraint.to_sql
|
46
|
-
end.join(' AND ')
|
27
|
+
non_immortal_constraints_sql = our_scope.arel.constraints.to_a.map do |constraint|
|
28
|
+
constraint.to_sql.split('AND').reject{|clause| clause.include?('deleted')}
|
29
|
+
end.flatten.join(' AND ')
|
47
30
|
|
48
31
|
new_scope = new_scope.merge(our_scope.except(:where))
|
49
32
|
new_scope = new_scope.where(non_immortal_constraints_sql)
|
50
33
|
|
51
|
-
unscoped do
|
52
|
-
|
53
|
-
yield
|
54
|
-
end
|
34
|
+
unscoped.merge(new_scope).scoping do
|
35
|
+
yield
|
55
36
|
end
|
56
37
|
end
|
57
38
|
|
58
39
|
def exists?(id = false)
|
59
|
-
where(:
|
40
|
+
where(deleted: false).exists?(id)
|
60
41
|
end
|
61
42
|
|
62
43
|
def count_with_deleted(*args)
|
@@ -67,24 +48,38 @@ module Immortal
|
|
67
48
|
|
68
49
|
def count_only_deleted(*args)
|
69
50
|
without_default_scope do
|
70
|
-
where(:
|
51
|
+
where(deleted: true).count(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def where_with_deleted(*args)
|
56
|
+
without_default_scope do
|
57
|
+
where(*args)
|
71
58
|
end
|
72
59
|
end
|
73
60
|
|
74
61
|
def find_with_deleted(*args)
|
62
|
+
ActiveSupport::Deprecation.warn('[immortal] we are deprecating #find_with_deleted use where_with_deleted instead')
|
75
63
|
without_default_scope do
|
76
64
|
find(*args)
|
77
65
|
end
|
78
66
|
end
|
79
67
|
|
68
|
+
def where_only_deleted(*args)
|
69
|
+
without_default_scope do
|
70
|
+
where(deleted: true).where(args)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
80
74
|
def find_only_deleted(*args)
|
75
|
+
ActiveSupport::Deprecation.warn('[immortal] we are deprecating #find_only_deleted use where_only_deleted instead')
|
81
76
|
without_default_scope do
|
82
|
-
where(:
|
77
|
+
where(deleted: true).find(*args)
|
83
78
|
end
|
84
79
|
end
|
85
80
|
|
86
81
|
def immortal_delete_all(conditions = nil)
|
87
|
-
unscoped.update_all(
|
82
|
+
unscoped.where(conditions).update_all(deleted: 1)
|
88
83
|
end
|
89
84
|
|
90
85
|
def delete_all!(*args)
|
@@ -92,7 +87,7 @@ module Immortal
|
|
92
87
|
end
|
93
88
|
|
94
89
|
def undeleted_clause_sql
|
95
|
-
unscoped.where(
|
90
|
+
unscoped.where(deleted: false).constraints.first.to_sql
|
96
91
|
end
|
97
92
|
|
98
93
|
def deleted_clause_sql
|
@@ -103,16 +98,23 @@ module Immortal
|
|
103
98
|
|
104
99
|
module InstanceMethods
|
105
100
|
def self.included(base)
|
101
|
+
unless base.table_exists? && base.columns_hash["deleted"] && !base.columns_hash["deleted"].null
|
102
|
+
Kernel.warn "[Immortal] The 'deleted' column in #{base.to_s} is nullable, change the column to not accept NULL values"
|
103
|
+
end
|
104
|
+
|
106
105
|
base.class_eval do
|
107
|
-
default_scope where(
|
106
|
+
default_scope { ->{ where(deleted: false) } } if arel_table[:deleted]
|
107
|
+
|
108
108
|
alias :mortal_destroy :destroy
|
109
109
|
alias :destroy :immortal_destroy
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
113
|
def immortal_destroy
|
114
|
-
|
115
|
-
|
114
|
+
with_transaction_returning_status do
|
115
|
+
run_callbacks :destroy do
|
116
|
+
destroy_without_callbacks
|
117
|
+
end
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
@@ -121,15 +123,23 @@ module Immortal
|
|
121
123
|
end
|
122
124
|
|
123
125
|
def destroy_without_callbacks
|
124
|
-
self.class.unscoped.update_all(
|
126
|
+
self.class.unscoped.where(id: id).update_all(deleted: true, updated_at: current_time_from_proper_timezone)
|
127
|
+
@destroyed = true
|
125
128
|
reload
|
126
129
|
freeze
|
127
130
|
end
|
128
131
|
|
129
132
|
def recover!
|
130
|
-
self.class.unscoped.update_all(
|
133
|
+
self.class.unscoped.where(id: id).update_all(deleted: false, updated_at: current_time_from_proper_timezone)
|
134
|
+
@destroyed = false
|
131
135
|
reload
|
132
136
|
end
|
133
137
|
|
138
|
+
private
|
139
|
+
|
140
|
+
def current_time_from_proper_timezone
|
141
|
+
ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
|
142
|
+
end
|
143
|
+
|
134
144
|
end
|
135
145
|
end
|
data/lib/immortal/belongs_to.rb
CHANGED
@@ -8,8 +8,8 @@ module Immortal
|
|
8
8
|
class << self
|
9
9
|
|
10
10
|
# Add with/how_deleted singular association readers
|
11
|
-
def belongs_to_mortal(name, options = {})
|
12
|
-
::Immortal::BelongsToBuilder.build(self, name, options)
|
11
|
+
def belongs_to_mortal(name, scope = nil, options = {})
|
12
|
+
::Immortal::BelongsToBuilder.build(self, name, scope, options)
|
13
13
|
end
|
14
14
|
|
15
15
|
alias_method :belongs_to_immortal, :belongs_to
|
@@ -12,15 +12,19 @@ module Immortal
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
+
def supports_indetity_map?
|
16
|
+
defined?(ActiveRecord::IdentityMap) && ActiveRecord::IdentityMap.enabled?
|
17
|
+
end
|
18
|
+
|
15
19
|
def reset_with_deleted
|
16
20
|
@with_deleted_loaded = false
|
17
|
-
ActiveRecord::IdentityMap.remove(with_deleted_target) if
|
21
|
+
ActiveRecord::IdentityMap.remove(with_deleted_target) if supports_indetity_map? && with_deleted_target
|
18
22
|
@with_deleted_target = nil
|
19
23
|
end
|
20
24
|
|
21
25
|
def reset_only_deleted
|
22
26
|
@only_deleted_loaded = false
|
23
|
-
ActiveRecord::IdentityMap.remove(only_deleted_target) if
|
27
|
+
ActiveRecord::IdentityMap.remove(only_deleted_target) if supports_indetity_map? && only_deleted_target
|
24
28
|
@only_deleted_target = nil
|
25
29
|
end
|
26
30
|
|
@@ -75,7 +79,7 @@ module Immortal
|
|
75
79
|
def load_with_deleted_target
|
76
80
|
if find_with_deleted_target?
|
77
81
|
begin
|
78
|
-
if
|
82
|
+
if supports_indetity_map? && association_class && association_class.respond_to?(:base_class)
|
79
83
|
@with_deleted_target = ActiveRecord::IdentityMap.get(association_class, owner[reflection.foreign_key])
|
80
84
|
end
|
81
85
|
rescue NameError
|
@@ -93,7 +97,7 @@ module Immortal
|
|
93
97
|
def load_only_deleted_target
|
94
98
|
if find_only_deleted_target?
|
95
99
|
begin
|
96
|
-
if
|
100
|
+
if supports_indetity_map? && association_class && association_class.respond_to?(:base_class)
|
97
101
|
@only_deleted_target = ActiveRecord::IdentityMap.get(association_class, owner[reflection.foreign_key])
|
98
102
|
end
|
99
103
|
rescue NameError
|
@@ -132,14 +136,14 @@ module Immortal
|
|
132
136
|
def find_with_deleted_target
|
133
137
|
return nil unless klass
|
134
138
|
klass.unscoped do
|
135
|
-
|
139
|
+
scope.first.tap { |record| set_inverse_instance(record) }
|
136
140
|
end
|
137
141
|
end
|
138
142
|
|
139
143
|
def find_only_deleted_target
|
140
144
|
return nil unless klass
|
141
145
|
klass.unscoped do
|
142
|
-
|
146
|
+
scope.where(deleted: true).first.tap { |record| set_inverse_instance(record) }
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
data/spec/immortal_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
2
2
|
|
3
3
|
describe Immortal do
|
4
4
|
before do
|
5
|
-
@m = ImmortalModel.create! :
|
5
|
+
@m = ImmortalModel.create! title: 'testing immortal'
|
6
6
|
end
|
7
7
|
|
8
8
|
it "should not be deleted from the database using #destroy" do
|
@@ -21,6 +21,12 @@ describe Immortal do
|
|
21
21
|
@m.should_not be_changed
|
22
22
|
end
|
23
23
|
|
24
|
+
it "should not be dirty using #destroy" do
|
25
|
+
expect {
|
26
|
+
@m.destroy
|
27
|
+
}.to change(@m, :updated_at)
|
28
|
+
end
|
29
|
+
|
24
30
|
it "should be deleted from the database using #destroy!" do
|
25
31
|
expect {
|
26
32
|
@m.destroy!
|
@@ -45,7 +51,7 @@ describe Immortal do
|
|
45
51
|
end
|
46
52
|
|
47
53
|
it "should count undeleted records by default" do
|
48
|
-
@m2 = ImmortalModel.create! :
|
54
|
+
@m2 = ImmortalModel.create! title: 'testing immortal again'
|
49
55
|
ImmortalModel.count_only_deleted.should == 0
|
50
56
|
|
51
57
|
@m.destroy
|
@@ -54,7 +60,7 @@ describe Immortal do
|
|
54
60
|
end
|
55
61
|
|
56
62
|
it "should find only deleted records" do
|
57
|
-
@m2 = ImmortalModel.create! :
|
63
|
+
@m2 = ImmortalModel.create! title: 'testing immortal again'
|
58
64
|
expect {
|
59
65
|
ImmortalModel.find_only_deleted(@m.id)
|
60
66
|
}.to raise_error(ActiveRecord::RecordNotFound)
|
@@ -68,7 +74,7 @@ describe Immortal do
|
|
68
74
|
end
|
69
75
|
|
70
76
|
it "should be able to count undeleted records" do
|
71
|
-
@m2 = ImmortalModel.create! :
|
77
|
+
@m2 = ImmortalModel.create! title: 'testing immortal again'
|
72
78
|
ImmortalModel.count.should == 2
|
73
79
|
|
74
80
|
@m.destroy
|
@@ -77,7 +83,7 @@ describe Immortal do
|
|
77
83
|
end
|
78
84
|
|
79
85
|
it "should be able to count all the records including deleted" do
|
80
|
-
@m2 = ImmortalModel.create! :
|
86
|
+
@m2 = ImmortalModel.create! title: 'testing immortal again'
|
81
87
|
@m.destroy
|
82
88
|
ImmortalModel.count_with_deleted.should == 2
|
83
89
|
end
|
@@ -89,8 +95,8 @@ describe Immortal do
|
|
89
95
|
end
|
90
96
|
|
91
97
|
it "should calculate without deleted" do
|
92
|
-
@m2 = ImmortalModel.create! :
|
93
|
-
@m3 = ImmortalModel.create! :
|
98
|
+
@m2 = ImmortalModel.create! value: 10
|
99
|
+
@m3 = ImmortalModel.create! value: 20
|
94
100
|
ImmortalModel.calculate(:sum, :value).should == 30
|
95
101
|
@m2.destroy
|
96
102
|
ImmortalModel.calculate(:sum, :value).should == 20
|
@@ -106,6 +112,19 @@ describe Immortal do
|
|
106
112
|
@m.after_d.should be_true
|
107
113
|
end
|
108
114
|
|
115
|
+
it "should execute the after_commit callback when immortally destroyed" do
|
116
|
+
@m.after_commit = false
|
117
|
+
@m.destroy
|
118
|
+
@m.after_commit.should be_true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not return true when a before hook halts" do
|
122
|
+
@m.before_return = false
|
123
|
+
@m.after_commit = false
|
124
|
+
@m.destroy.should be_false
|
125
|
+
@m.after_commit.should_not be_true
|
126
|
+
end
|
127
|
+
|
109
128
|
it "should not execute the before_update callback when immortally destroyed" do
|
110
129
|
@m.destroy
|
111
130
|
@m.before_u.should be_nil
|
@@ -148,22 +167,17 @@ describe Immortal do
|
|
148
167
|
it "should be recoverable" do
|
149
168
|
@m.destroy
|
150
169
|
@m = ImmortalModel.find_with_deleted(@m.id)
|
151
|
-
|
170
|
+
expect {
|
171
|
+
@m.recover!
|
172
|
+
}.to change(@m, :updated_at)
|
152
173
|
@m.should_not be_frozen
|
153
174
|
@m.should_not be_changed
|
154
175
|
ImmortalModel.first.should == @m
|
155
176
|
end
|
156
177
|
|
157
|
-
it "should consider an object with deleted = nil as not deleted" do
|
158
|
-
@m2 = ImmortalModel.create! :deleted => nil
|
159
|
-
@m2.deleted.should be_nil
|
160
|
-
@m2.should_not be_deleted
|
161
|
-
ImmortalModel.count.should == 2
|
162
|
-
end
|
163
|
-
|
164
178
|
it "should consider an Many-to-many association with through as deleted when the join is deleted." do
|
165
|
-
@n = ImmortalNode.create! :
|
166
|
-
@join = ImmortalJoin.create! :
|
179
|
+
@n = ImmortalNode.create! title: 'testing association'
|
180
|
+
@join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
|
167
181
|
|
168
182
|
@m.nodes.count.should == 1
|
169
183
|
@n.models.count.should == 1
|
@@ -175,14 +189,14 @@ describe Immortal do
|
|
175
189
|
end
|
176
190
|
|
177
191
|
it "should only immortally delete scoped associations, NOT ALL RECORDS" do
|
178
|
-
n1 = ImmortalNode.create! :
|
179
|
-
j1 = ImmortalJoin.create! :
|
192
|
+
n1 = ImmortalNode.create! title: 'testing association 1'
|
193
|
+
j1 = ImmortalJoin.create! immortal_model: @m, immortal_node: n1
|
180
194
|
|
181
|
-
n2 = ImmortalNode.create! :
|
182
|
-
j2 = ImmortalJoin.create! :
|
195
|
+
n2 = ImmortalNode.create! title: 'testing association 2'
|
196
|
+
j2 = ImmortalJoin.create! immortal_model: @m, immortal_node: n2
|
183
197
|
|
184
|
-
n3 = ImmortalNode.create! :
|
185
|
-
j3 = ImmortalJoin.create! :
|
198
|
+
n3 = ImmortalNode.create! title: 'testing association 3'
|
199
|
+
j3 = ImmortalJoin.create! immortal_node: n3
|
186
200
|
|
187
201
|
@m.destroy
|
188
202
|
|
@@ -199,9 +213,9 @@ describe Immortal do
|
|
199
213
|
end
|
200
214
|
|
201
215
|
it "should reload immortal polymorphic associations using default reader" do
|
202
|
-
node = ImmortalNode.create! :
|
203
|
-
target_1 = ImmortalSomeTarget.create! :
|
204
|
-
target_2 = ImmortalSomeOtherTarget.create! :
|
216
|
+
node = ImmortalNode.create! title: 'testing association 1'
|
217
|
+
target_1 = ImmortalSomeTarget.create! title: 'target 1'
|
218
|
+
target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
|
205
219
|
|
206
220
|
node.target.should be_nil
|
207
221
|
node.target = target_1
|
@@ -216,9 +230,9 @@ describe Immortal do
|
|
216
230
|
|
217
231
|
it "should reload immortal polymorphic associations using deleted reader" do
|
218
232
|
#setup
|
219
|
-
node = ImmortalNode.create! :
|
220
|
-
target_1 = ImmortalSomeTarget.create! :
|
221
|
-
target_2 = ImmortalSomeOtherTarget.create! :
|
233
|
+
node = ImmortalNode.create! title: 'testing association 1'
|
234
|
+
target_1 = ImmortalSomeTarget.create! title: 'target 1'
|
235
|
+
target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
|
222
236
|
|
223
237
|
#confirm initial state
|
224
238
|
node.target.should be_nil
|
@@ -250,9 +264,9 @@ describe Immortal do
|
|
250
264
|
|
251
265
|
it "should reload immortal polymorphic associations using deleted reader (direct assignment)" do
|
252
266
|
#setup
|
253
|
-
node = ImmortalNode.create! :
|
254
|
-
target_1 = ImmortalSomeTarget.create! :
|
255
|
-
target_2 = ImmortalSomeOtherTarget.create! :
|
267
|
+
node = ImmortalNode.create! title: 'testing association 1'
|
268
|
+
target_1 = ImmortalSomeTarget.create! title: 'target 1'
|
269
|
+
target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
|
256
270
|
|
257
271
|
#confirm initial state
|
258
272
|
node.target.should be_nil
|
@@ -282,9 +296,9 @@ describe Immortal do
|
|
282
296
|
|
283
297
|
it "deleted readers should respect staleness" do
|
284
298
|
#setup
|
285
|
-
node = ImmortalNode.create! :
|
286
|
-
target_1 = ImmortalSomeTarget.create! :
|
287
|
-
target_2 = ImmortalSomeOtherTarget.create! :
|
299
|
+
node = ImmortalNode.create! title: 'testing association 1'
|
300
|
+
target_1 = ImmortalSomeTarget.create! title: 'target 1'
|
301
|
+
target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
|
288
302
|
|
289
303
|
#confirm initial state
|
290
304
|
node.target.should be_nil
|
@@ -324,12 +338,12 @@ describe Immortal do
|
|
324
338
|
end
|
325
339
|
|
326
340
|
it "should not unscope associations when using with_deleted scope" do
|
327
|
-
m1 = ImmortalModel.create! :
|
328
|
-
n1 = ImmortalNode.create! :
|
329
|
-
|
341
|
+
m1 = ImmortalModel.create! title: 'previously created model'
|
342
|
+
n1 = ImmortalNode.create! title: 'previously created association'
|
343
|
+
ImmortalJoin.create! immortal_model: m1, immortal_node: n1
|
330
344
|
|
331
|
-
@n = ImmortalNode.create! :
|
332
|
-
@join = ImmortalJoin.create! :
|
345
|
+
@n = ImmortalNode.create! title: 'testing association'
|
346
|
+
@join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
|
333
347
|
|
334
348
|
@join.destroy
|
335
349
|
|
@@ -341,12 +355,12 @@ describe Immortal do
|
|
341
355
|
end
|
342
356
|
|
343
357
|
it "should not unscope associations when using only_deleted scope" do
|
344
|
-
m1 = ImmortalModel.create! :
|
345
|
-
n1 = ImmortalNode.create! :
|
346
|
-
|
358
|
+
m1 = ImmortalModel.create! title: 'previously created model'
|
359
|
+
n1 = ImmortalNode.create! title: 'previously created association'
|
360
|
+
ImmortalJoin.create! immortal_model: m1, immortal_node: n1
|
347
361
|
|
348
|
-
@n = ImmortalNode.create! :
|
349
|
-
@join = ImmortalJoin.create! :
|
362
|
+
@n = ImmortalNode.create! title: 'testing association'
|
363
|
+
@join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
|
350
364
|
|
351
365
|
@join.destroy
|
352
366
|
|
@@ -358,4 +372,12 @@ describe Immortal do
|
|
358
372
|
@n.joins.count_only_deleted.should == 1
|
359
373
|
end
|
360
374
|
|
375
|
+
it 'warn when deleted column is nullable' do
|
376
|
+
Kernel.should_receive(:warn)
|
377
|
+
|
378
|
+
class ImmortalNullableDeleted
|
379
|
+
include Immortal
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
361
383
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -15,7 +15,7 @@ RSpec.configure do |config|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
|
18
|
-
ActiveRecord::Base.establish_connection(:
|
18
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
19
19
|
ActiveRecord::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
|
20
20
|
|
21
21
|
old_stdout = $stdout
|
@@ -26,13 +26,13 @@ begin
|
|
26
26
|
create_table :immortal_models do |t|
|
27
27
|
t.string :title
|
28
28
|
t.integer :value
|
29
|
-
t.boolean :deleted, :
|
29
|
+
t.boolean :deleted, default: false, null: false
|
30
30
|
t.timestamps
|
31
31
|
end
|
32
32
|
create_table :immortal_joins do |t|
|
33
33
|
t.integer :immortal_model_id
|
34
34
|
t.integer :immortal_node_id
|
35
|
-
t.boolean :deleted, :
|
35
|
+
t.boolean :deleted, default: false, null: false
|
36
36
|
t.timestamps
|
37
37
|
end
|
38
38
|
create_table :immortal_nodes do |t|
|
@@ -40,19 +40,25 @@ begin
|
|
40
40
|
t.string :target_type
|
41
41
|
t.string :title
|
42
42
|
t.integer :value
|
43
|
-
t.boolean :deleted, :
|
43
|
+
t.boolean :deleted, default: false, null: false
|
44
44
|
t.timestamps
|
45
45
|
end
|
46
46
|
|
47
47
|
create_table :immortal_some_targets do |t|
|
48
48
|
t.string :title
|
49
|
-
t.boolean :deleted, :
|
49
|
+
t.boolean :deleted, default: false, null: false
|
50
50
|
t.timestamps
|
51
51
|
end
|
52
52
|
|
53
53
|
create_table :immortal_some_other_targets do |t|
|
54
54
|
t.string :title
|
55
|
-
t.boolean :deleted, :
|
55
|
+
t.boolean :deleted, default: false, null: false
|
56
|
+
t.timestamps
|
57
|
+
end
|
58
|
+
|
59
|
+
create_table :immortal_nullable_deleteds do |t|
|
60
|
+
t.string :title
|
61
|
+
t.boolean :deleted, default: false
|
56
62
|
t.timestamps
|
57
63
|
end
|
58
64
|
end
|
@@ -64,53 +70,56 @@ class ImmortalJoin < ActiveRecord::Base
|
|
64
70
|
include Immortal
|
65
71
|
|
66
72
|
belongs_to :immortal_model
|
67
|
-
belongs_to :immortal_node, :
|
73
|
+
belongs_to :immortal_node, dependent: :destroy
|
68
74
|
end
|
69
75
|
|
70
76
|
class ImmortalNode < ActiveRecord::Base
|
71
77
|
include Immortal
|
72
78
|
|
73
79
|
has_many :immortal_joins
|
74
|
-
has_many :immortal_models, :
|
80
|
+
has_many :immortal_models, through: :immortal_joins
|
75
81
|
|
76
|
-
has_many :joins, :
|
77
|
-
has_many :models, :
|
82
|
+
has_many :joins, class_name: 'ImmortalJoin'
|
83
|
+
has_many :models, through: :joins, source: :immortal_model
|
78
84
|
|
79
|
-
belongs_to :target, :
|
85
|
+
belongs_to :target, polymorphic: true
|
80
86
|
end
|
81
87
|
|
82
88
|
class ImmortalSomeTarget < ActiveRecord::Base
|
83
89
|
include Immortal
|
84
90
|
|
85
|
-
has_many :immortal_nodes, :
|
91
|
+
has_many :immortal_nodes, as: :target
|
86
92
|
end
|
87
93
|
|
88
94
|
class ImmortalSomeOtherTarget < ActiveRecord::Base
|
89
95
|
include Immortal
|
90
96
|
|
91
|
-
has_many :immortal_nodes, :
|
97
|
+
has_many :immortal_nodes, as: :target
|
92
98
|
end
|
93
99
|
|
94
100
|
|
95
101
|
class ImmortalModel < ActiveRecord::Base
|
96
102
|
include Immortal
|
97
103
|
|
98
|
-
has_many :immortal_nodes, :
|
99
|
-
has_many :immortal_joins, :
|
104
|
+
has_many :immortal_nodes, through: :immortal_joins, dependent: :destroy
|
105
|
+
has_many :immortal_joins, dependent: :delete_all
|
100
106
|
|
101
|
-
has_many :joins, :
|
102
|
-
has_many :nodes, :
|
107
|
+
has_many :joins, class_name: 'ImmortalJoin', dependent: :delete_all
|
108
|
+
has_many :nodes, through: :joins, source: :immortal_node, dependent: :destroy
|
103
109
|
|
104
|
-
attr_accessor :before_d, :after_d, :before_u, :after_u
|
110
|
+
attr_accessor :before_d, :after_d, :before_u, :after_u, :after_commit, :before_return
|
105
111
|
|
106
112
|
before_destroy :set_before
|
107
113
|
after_destroy :set_after
|
108
114
|
before_update :set_before_update
|
109
115
|
after_update :set_after_update
|
116
|
+
after_commit :set_after_commit, on: :destroy
|
110
117
|
|
111
118
|
private
|
119
|
+
|
112
120
|
def set_before
|
113
121
|
@before_d = true
|
122
|
+
@before_return
|
114
123
|
end
|
115
124
|
|
116
125
|
def set_after
|
@@ -121,9 +130,16 @@ class ImmortalModel < ActiveRecord::Base
|
|
121
130
|
@after_u = true
|
122
131
|
end
|
123
132
|
|
133
|
+
def set_after_commit
|
134
|
+
@after_commit = true
|
135
|
+
end
|
136
|
+
|
124
137
|
def set_before_update
|
125
138
|
@before_u = true
|
126
139
|
end
|
127
140
|
|
128
141
|
end
|
129
142
|
|
143
|
+
class ImmortalNullableDeleted < ActiveRecord::Base
|
144
|
+
end
|
145
|
+
|
metadata
CHANGED
@@ -1,51 +1,92 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: immortal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Jordi Romero
|
9
8
|
- Saimon Moore
|
9
|
+
- Pau Ramon
|
10
|
+
- Carlos Saura
|
11
|
+
- Andres Bravo
|
12
|
+
- Fran Casas
|
13
|
+
- Pau Perez
|
10
14
|
autorequire:
|
11
15
|
bindir: bin
|
12
16
|
cert_chain: []
|
13
|
-
date:
|
17
|
+
date: 2016-11-24 00:00:00.000000000 Z
|
14
18
|
dependencies:
|
15
19
|
- !ruby/object:Gem::Dependency
|
16
20
|
name: activerecord
|
17
|
-
requirement:
|
18
|
-
none: false
|
21
|
+
requirement: !ruby/object:Gem::Requirement
|
19
22
|
requirements:
|
20
|
-
- - ~>
|
23
|
+
- - "~>"
|
21
24
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
25
|
+
version: 4.0.0
|
23
26
|
type: :runtime
|
24
27
|
prerelease: false
|
25
|
-
version_requirements:
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.0.0
|
26
33
|
- !ruby/object:Gem::Dependency
|
27
34
|
name: rspec
|
28
|
-
requirement:
|
29
|
-
none: false
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
|
-
- - ~>
|
37
|
+
- - "~>"
|
32
38
|
- !ruby/object:Gem::Version
|
33
39
|
version: 2.6.0
|
34
40
|
type: :development
|
35
41
|
prerelease: false
|
36
|
-
version_requirements:
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.6.0
|
37
47
|
- !ruby/object:Gem::Dependency
|
38
48
|
name: sqlite3
|
39
|
-
requirement:
|
40
|
-
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: byebug
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
71
|
requirements:
|
42
|
-
- -
|
72
|
+
- - ">="
|
43
73
|
- !ruby/object:Gem::Version
|
44
74
|
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rake
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '10.0'
|
45
82
|
type: :development
|
46
83
|
prerelease: false
|
47
|
-
version_requirements:
|
48
|
-
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '10.0'
|
89
|
+
description: Typical paranoid gem built for Rails 4 and with the minimum code needed
|
49
90
|
to satisfy acts_as_paranoid's API
|
50
91
|
email:
|
51
92
|
- jordi@jrom.net
|
@@ -54,9 +95,9 @@ executables: []
|
|
54
95
|
extensions: []
|
55
96
|
extra_rdoc_files: []
|
56
97
|
files:
|
57
|
-
- .gitignore
|
98
|
+
- ".gitignore"
|
58
99
|
- Gemfile
|
59
|
-
-
|
100
|
+
- LICENSE
|
60
101
|
- README.md
|
61
102
|
- Rakefile
|
62
103
|
- immortal.gemspec
|
@@ -67,27 +108,27 @@ files:
|
|
67
108
|
- spec/immortal_spec.rb
|
68
109
|
- spec/spec_helper.rb
|
69
110
|
homepage: http://github.com/teambox/immortal
|
70
|
-
licenses:
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
metadata: {}
|
71
114
|
post_install_message:
|
72
115
|
rdoc_options: []
|
73
116
|
require_paths:
|
74
117
|
- lib
|
75
118
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
119
|
requirements:
|
78
|
-
- -
|
120
|
+
- - ">="
|
79
121
|
- !ruby/object:Gem::Version
|
80
122
|
version: '0'
|
81
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
124
|
requirements:
|
84
|
-
- -
|
125
|
+
- - ">="
|
85
126
|
- !ruby/object:Gem::Version
|
86
127
|
version: '0'
|
87
128
|
requirements: []
|
88
129
|
rubyforge_project:
|
89
|
-
rubygems_version:
|
130
|
+
rubygems_version: 2.4.5.1
|
90
131
|
signing_key:
|
91
|
-
specification_version:
|
92
|
-
summary: Replacement for acts_as_paranoid for Rails
|
132
|
+
specification_version: 4
|
133
|
+
summary: Replacement for acts_as_paranoid for Rails 4
|
93
134
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
immortal (1.0.3)
|
5
|
-
activerecord (~> 3.1.1)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: http://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (3.1.1)
|
11
|
-
activesupport (= 3.1.1)
|
12
|
-
builder (~> 3.0.0)
|
13
|
-
i18n (~> 0.6)
|
14
|
-
activerecord (3.1.1)
|
15
|
-
activemodel (= 3.1.1)
|
16
|
-
activesupport (= 3.1.1)
|
17
|
-
arel (~> 2.2.1)
|
18
|
-
tzinfo (~> 0.3.29)
|
19
|
-
activesupport (3.1.1)
|
20
|
-
multi_json (~> 1.0)
|
21
|
-
arel (2.2.1)
|
22
|
-
builder (3.0.0)
|
23
|
-
diff-lcs (1.1.3)
|
24
|
-
i18n (0.6.0)
|
25
|
-
multi_json (1.0.3)
|
26
|
-
rspec (2.6.0)
|
27
|
-
rspec-core (~> 2.6.0)
|
28
|
-
rspec-expectations (~> 2.6.0)
|
29
|
-
rspec-mocks (~> 2.6.0)
|
30
|
-
rspec-core (2.6.4)
|
31
|
-
rspec-expectations (2.6.0)
|
32
|
-
diff-lcs (~> 1.1.2)
|
33
|
-
rspec-mocks (2.6.0)
|
34
|
-
sqlite3 (1.3.4)
|
35
|
-
tzinfo (0.3.30)
|
36
|
-
|
37
|
-
PLATFORMS
|
38
|
-
ruby
|
39
|
-
|
40
|
-
DEPENDENCIES
|
41
|
-
immortal!
|
42
|
-
rspec (~> 2.6.0)
|
43
|
-
sqlite3
|