destroyed_at 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/destroyed_at.gemspec +4 -2
- data/lib/.DS_Store +0 -0
- data/lib/destroyed_at.rb +32 -8
- data/lib/destroyed_at/belongs_to_association.rb +15 -0
- data/lib/destroyed_at/has_many_association.rb +14 -0
- data/lib/destroyed_at/has_one_association.rb +15 -0
- data/lib/destroyed_at/version.rb +1 -1
- data/test/destroyed_at_test.rb +79 -12
- data/test/test_helper.rb +14 -7
- metadata +13 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 072d8f78b587daebb48a6fa406287342c2e1ee3a
|
4
|
+
data.tar.gz: 6e963e35a47e92e114fc14038e2e8cc0734bf4b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fe52260f693cdd042dc38b26b55c51fbd2b1ee3043c5ef7273154fd78d3b91c54dc84a36a8a70e92498df6a5ec3b1dfd3a0628540cac6c35f66a8aceeb00171
|
7
|
+
data.tar.gz: 10eeacbd7a71381ddd8401d9069f4cc5d3b1a195b0338d4a46b33d780327b2a57041b3af1ced43e1fa193f25c741ed59c0e47c0bff86cc3e5511bba992d96be7
|
data/destroyed_at.gemspec
CHANGED
@@ -17,10 +17,12 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
+
spec.required_ruby_version = '>= 2.0'
|
21
|
+
|
20
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
23
|
spec.add_development_dependency "rake"
|
22
|
-
spec.add_development_dependency "activerecord", "~>
|
23
|
-
spec.add_development_dependency "minitest"
|
24
|
+
spec.add_development_dependency "activerecord", "~> 4.0.0"
|
25
|
+
spec.add_development_dependency "minitest"
|
24
26
|
spec.add_development_dependency "m"
|
25
27
|
spec.add_development_dependency "sqlite3"
|
26
28
|
spec.add_development_dependency "byebug"
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/destroyed_at.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'destroyed_at/version'
|
2
|
+
require 'destroyed_at/belongs_to_association'
|
3
|
+
require 'destroyed_at/has_many_association'
|
4
|
+
require 'destroyed_at/has_one_association'
|
2
5
|
|
3
6
|
module DestroyedAt
|
4
7
|
def self.included(klass)
|
@@ -10,11 +13,12 @@ module DestroyedAt
|
|
10
13
|
end
|
11
14
|
|
12
15
|
# Set an object's destroyed_at time.
|
13
|
-
def destroy
|
16
|
+
def destroy(timestamp = nil)
|
17
|
+
timestamp ||= current_time_from_proper_timezone
|
18
|
+
raw_write_attribute(:destroyed_at, timestamp)
|
14
19
|
run_callbacks(:destroy) do
|
15
20
|
destroy_associations
|
16
|
-
self.destroyed_at
|
17
|
-
self.save(callbacks: false)
|
21
|
+
self.class.unscoped.where(self.class.primary_key => id).update_all(destroyed_at: timestamp)
|
18
22
|
@destroyed = true
|
19
23
|
end
|
20
24
|
end
|
@@ -23,15 +27,25 @@ module DestroyedAt
|
|
23
27
|
def restore
|
24
28
|
state = nil
|
25
29
|
run_callbacks(:restore) do
|
26
|
-
self.destroyed_at
|
27
|
-
if state = self.save(callbacks: false, validate: false)
|
28
|
-
@destroyed = false
|
30
|
+
if state = (self.class.unscoped.where(self.class.primary_key => id).update_all(destroyed_at: nil) == 1)
|
29
31
|
_restore_associations
|
32
|
+
raw_write_attribute(:destroyed_at, nil)
|
33
|
+
@destroyed = false
|
34
|
+
true
|
30
35
|
end
|
31
36
|
end
|
32
37
|
state
|
33
38
|
end
|
34
39
|
|
40
|
+
def persisted?
|
41
|
+
!new_record? && destroyed_at.present? || super
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete
|
45
|
+
self.destroyed_at = nil
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
35
49
|
private
|
36
50
|
|
37
51
|
def _set_destruction_state
|
@@ -43,10 +57,20 @@ module DestroyedAt
|
|
43
57
|
def _restore_associations
|
44
58
|
reflections.select { |key, value| value.options[:dependent] == :destroy }.keys.each do |key|
|
45
59
|
assoc = association(key)
|
60
|
+
reload_association = false
|
46
61
|
if assoc.options[:through] && assoc.options[:dependent] == :destroy
|
47
62
|
assoc = association(assoc.options[:through])
|
48
63
|
end
|
49
|
-
assoc.association_scope.each
|
64
|
+
assoc.association_scope.each do |r|
|
65
|
+
if r.respond_to?(:restore) && r.destroyed_at == self.destroyed_at
|
66
|
+
r.restore
|
67
|
+
reload_association = true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if reload_association
|
72
|
+
assoc.reload
|
73
|
+
end
|
50
74
|
end
|
51
75
|
end
|
52
76
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DestroyedAt
|
2
|
+
module BelongsToAssociation
|
3
|
+
def handle_dependency
|
4
|
+
if load_target
|
5
|
+
if options[:dependent] == :destroy && target.respond_to?(:destroyed_at)
|
6
|
+
target.destroy(owner.destroyed_at)
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Associations::BelongsToAssociation.send(:prepend, DestroyedAt::BelongsToAssociation)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DestroyedAt
|
2
|
+
module HasManyAssociation
|
3
|
+
def delete_records(records, method)
|
4
|
+
if method == :destroy
|
5
|
+
records.each { |r| r.destroy(owner.destroyed_at) }
|
6
|
+
update_counter(-records.length) unless inverse_updates_counter_cache?
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveRecord::Associations::HasManyAssociation.send(:prepend, DestroyedAt::HasManyAssociation)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DestroyedAt
|
2
|
+
module HasOneAssociation
|
3
|
+
def delete(method = options[:dependent])
|
4
|
+
if load_target
|
5
|
+
if method == :destroy && target.respond_to?(:destroyed_at)
|
6
|
+
target.destroy(owner.destroyed_at)
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Associations::HasOneAssociation.send(:prepend, DestroyedAt::HasOneAssociation)
|
data/lib/destroyed_at/version.rb
CHANGED
data/test/destroyed_at_test.rb
CHANGED
@@ -5,7 +5,7 @@ describe 'Destroying AR models' do
|
|
5
5
|
user = User.create
|
6
6
|
user.destroy
|
7
7
|
User.all.must_be_empty
|
8
|
-
User.unscoped.
|
8
|
+
User.unscoped.load.wont_be_empty
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'Destroying a model will set the timestamp it was destroyed at' do
|
@@ -22,6 +22,7 @@ describe 'Destroying AR models' do
|
|
22
22
|
User.all.must_be_empty
|
23
23
|
user.reload
|
24
24
|
user.restore
|
25
|
+
user.destroyed_at.must_be_nil
|
25
26
|
User.all.wont_be_empty
|
26
27
|
end
|
27
28
|
|
@@ -56,9 +57,11 @@ describe 'Destroying AR models' do
|
|
56
57
|
end
|
57
58
|
|
58
59
|
it 'can restore relationships' do
|
59
|
-
|
60
|
-
|
60
|
+
timestamp = DateTime.current
|
61
|
+
user = User.create(:destroyed_at => timestamp)
|
62
|
+
Profile.create(:destroyed_at => timestamp, :user => user)
|
61
63
|
Profile.count.must_equal 0
|
64
|
+
user.reload
|
62
65
|
user.restore
|
63
66
|
Profile.count.must_equal 1
|
64
67
|
end
|
@@ -71,20 +74,23 @@ describe 'Destroying AR models' do
|
|
71
74
|
end
|
72
75
|
|
73
76
|
it 'will respect has many associations' do
|
74
|
-
|
75
|
-
|
77
|
+
timestamp = DateTime.current
|
78
|
+
user = User.create(:destroyed_at => timestamp)
|
79
|
+
Dinner.create(:destroyed_at => timestamp, :user => user)
|
76
80
|
Dinner.count.must_equal 0
|
81
|
+
user.reload
|
77
82
|
user.restore
|
78
83
|
Dinner.count.must_equal 1
|
79
84
|
end
|
80
85
|
|
81
86
|
it 'will respect has many through associations' do
|
82
|
-
|
83
|
-
user = User.create(:destroyed_at =>
|
87
|
+
timestamp = DateTime.current
|
88
|
+
user = User.create(:destroyed_at => timestamp)
|
84
89
|
car = Car.create
|
85
|
-
fleet = Fleet.create(:destroyed_at =>
|
90
|
+
fleet = Fleet.create(:destroyed_at => timestamp, :car => car)
|
86
91
|
user.fleets = [fleet]
|
87
92
|
user.cars.count.must_equal 0
|
93
|
+
user.reload
|
88
94
|
user.restore
|
89
95
|
user.cars.count.must_equal 1
|
90
96
|
end
|
@@ -120,14 +126,75 @@ describe 'Destroying AR models' do
|
|
120
126
|
it 'skips callbacks' do
|
121
127
|
user = User.create
|
122
128
|
user.destroy
|
123
|
-
user.
|
129
|
+
user.before_update_count.must_equal nil
|
124
130
|
user.restore
|
125
|
-
user.
|
131
|
+
user.before_update_count.must_equal nil
|
126
132
|
end
|
127
133
|
|
128
134
|
it 'skips validations on restore' do
|
129
|
-
user = User.create
|
135
|
+
user = User.create
|
136
|
+
user.validation_count.must_equal 1
|
137
|
+
user.destroy
|
138
|
+
user.validation_count.must_equal 1
|
139
|
+
user.restore
|
140
|
+
user.validation_count.must_equal 1
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'stays persisted after destruction' do
|
144
|
+
user = User.create
|
145
|
+
user.destroy
|
146
|
+
user.persisted?.must_equal true
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'does not allow new records with destroyed_at columns present to be marked persisted' do
|
150
|
+
user = User.new(destroyed_at: Time.now)
|
151
|
+
user.persisted?.must_equal false
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'is not persisted after deletion' do
|
155
|
+
user = User.create
|
156
|
+
user.delete
|
157
|
+
user.persisted?.must_equal false
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'can delete destroyed records and they are marked as not persisted' do
|
161
|
+
user = User.create
|
162
|
+
user.destroy
|
163
|
+
user.persisted?.must_equal true
|
164
|
+
user.delete
|
165
|
+
user.persisted?.must_equal false
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'only restores dependencies destroyed with parent with has many' do
|
169
|
+
user = User.create
|
170
|
+
dinner_one = Dinner.create(user: user, destroyed_at: Time.now - 1.day)
|
171
|
+
dinner_two = Dinner.create(user: user)
|
172
|
+
user.destroy
|
173
|
+
user.restore
|
174
|
+
user.dinners.include?(dinner_one).must_equal false
|
175
|
+
user.dinners.include?(dinner_two).must_equal true
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'only restores dependencies destroyed with parent with has one' do
|
179
|
+
user = User.create
|
180
|
+
profile_1 = Profile.create(user: user, destroyed_at: Time.now - 1.day)
|
181
|
+
profile_2 = Profile.create(user: user)
|
130
182
|
user.destroy
|
131
|
-
user.restore
|
183
|
+
user.restore
|
184
|
+
user.profile.must_equal profile_2
|
185
|
+
profile_1.reload
|
186
|
+
profile_1.destroyed_at.wont_equal nil
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'destroys and restores dependencies in a belongs_to relationship' do
|
190
|
+
user = User.create
|
191
|
+
show = Show.create(user: user)
|
192
|
+
show.destroy
|
193
|
+
show.reload
|
194
|
+
user.reload
|
195
|
+
user.destroyed_at.wont_equal nil
|
196
|
+
show.restore
|
197
|
+
user.reload
|
198
|
+
user.destroyed_at.must_equal nil
|
132
199
|
end
|
133
200
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'bundler/setup'
|
2
|
+
require 'active_record'
|
2
3
|
require 'destroyed_at'
|
3
4
|
require 'minitest/autorun'
|
4
|
-
require 'active_record'
|
5
5
|
require 'byebug'
|
6
6
|
require 'timecop'
|
7
7
|
require 'database_cleaner'
|
8
8
|
|
9
|
-
class
|
9
|
+
class MiniTest::Spec
|
10
10
|
class << self
|
11
11
|
alias :context :describe
|
12
12
|
end
|
@@ -42,15 +42,21 @@ class User < ActiveRecord::Base
|
|
42
42
|
has_one :show
|
43
43
|
has_many :fleets
|
44
44
|
has_many :cars, :through => :fleets, :dependent => :destroy
|
45
|
-
|
45
|
+
before_update :increment_callback_counter
|
46
|
+
validate :increment_validation_counter
|
46
47
|
|
47
|
-
attr_accessor :
|
48
|
+
attr_accessor :before_update_count, :validation_count
|
48
49
|
|
49
50
|
private
|
50
51
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
52
|
+
def increment_callback_counter
|
53
|
+
self.before_update_count ||= 0
|
54
|
+
self.before_update_count = self.before_update_count + 1
|
55
|
+
end
|
56
|
+
|
57
|
+
def increment_validation_counter
|
58
|
+
self.validation_count ||= 0
|
59
|
+
self.validation_count = self.validation_count + 1
|
54
60
|
end
|
55
61
|
end
|
56
62
|
|
@@ -89,6 +95,7 @@ end
|
|
89
95
|
|
90
96
|
class Show < ActiveRecord::Base
|
91
97
|
include DestroyedAt
|
98
|
+
belongs_to :user, :dependent => :destroy
|
92
99
|
end
|
93
100
|
|
94
101
|
class Fleet < ActiveRecord::Base
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: destroyed_at
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Dupuis Jr.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 4.0.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
|
-
version:
|
54
|
+
version: 4.0.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: m
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,7 +150,11 @@ files:
|
|
150
150
|
- README.md
|
151
151
|
- Rakefile
|
152
152
|
- destroyed_at.gemspec
|
153
|
+
- lib/.DS_Store
|
153
154
|
- lib/destroyed_at.rb
|
155
|
+
- lib/destroyed_at/belongs_to_association.rb
|
156
|
+
- lib/destroyed_at/has_many_association.rb
|
157
|
+
- lib/destroyed_at/has_one_association.rb
|
154
158
|
- lib/destroyed_at/version.rb
|
155
159
|
- test/destroyed_at_test.rb
|
156
160
|
- test/test_helper.rb
|
@@ -166,7 +170,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
166
170
|
requirements:
|
167
171
|
- - '>='
|
168
172
|
- !ruby/object:Gem::Version
|
169
|
-
version: '0'
|
173
|
+
version: '2.0'
|
170
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
175
|
requirements:
|
172
176
|
- - '>='
|