destroyed_at 0.1.5 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28d8c5c555222b4e7e45c3a782e60b7026970c37
4
- data.tar.gz: 7f343f2ec3da1c7baec08b06c2433a29a2ab0fc5
3
+ metadata.gz: 072d8f78b587daebb48a6fa406287342c2e1ee3a
4
+ data.tar.gz: 6e963e35a47e92e114fc14038e2e8cc0734bf4b0
5
5
  SHA512:
6
- metadata.gz: 068490e630e8dd369dc013ffa5e5ac9a44cae31bbd88d4e080b1621154dd85da503783d3bf1fd9bb082dbcff97d1079d98561a6b27760ff2782681fbee7bd22f
7
- data.tar.gz: 9f4f2b3dccba9fa4046039e055ed1726d159dea30f4781aac80ab29e1fceea3570e631a74867e94afbd8808da4767a3eeda772c11041aa4dc01a2c8895b2facc
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", "~> 3.2"
23
- spec.add_development_dependency "minitest", "~> 5"
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 "destroyed_at/version"
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 = current_time_from_proper_timezone
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 = nil
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 { |r| r.restore if r.respond_to? :restore }
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)
@@ -1,3 +1,3 @@
1
1
  module DestroyedAt
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.all.wont_be_empty
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
- user = User.create(:destroyed_at => DateTime.current)
60
- Profile.create(:destroyed_at => DateTime.current, :user => user)
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
- user = User.create(:destroyed_at => DateTime.current)
75
- Dinner.create(:destroyed_at => DateTime.current, :user => user)
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
- #user = User.create(:destroyed_at => DateTime.current, :fleets => [Fleet.new(:destroyed_at => DateTime.current, :car => Car.new)])
83
- user = User.create(:destroyed_at => DateTime.current)
87
+ timestamp = DateTime.current
88
+ user = User.create(:destroyed_at => timestamp)
84
89
  car = Car.create
85
- fleet = Fleet.create(:destroyed_at => DateTime.current, :car => car)
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.before_save_count.must_equal nil
129
+ user.before_update_count.must_equal nil
124
130
  user.restore
125
- user.before_save_count.must_equal nil
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(nil_attribute: '123')
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.must_equal true
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 Minitest::Spec
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
- before_save :increment_counter
45
+ before_update :increment_callback_counter
46
+ validate :increment_validation_counter
46
47
 
47
- attr_accessor :before_save_count, :nil_attribute
48
+ attr_accessor :before_update_count, :validation_count
48
49
 
49
50
  private
50
51
 
51
- def increment_counter
52
- @counter ||= 0
53
- @counter = @counter + 1
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.1.5
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-09-30 00:00:00.000000000 Z
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: '3.2'
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: '3.2'
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: '5'
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: '5'
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
  - - '>='