kakurenbo 0.1.3 → 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 +4 -4
- data/.travis.yml +2 -3
- data/Gemfile +4 -0
- data/README.md +24 -12
- data/kakurenbo.gemspec +2 -2
- data/lib/kakurenbo.rb +8 -1
- data/lib/kakurenbo/{soft_delete_core.rb → core.rb} +76 -53
- data/lib/kakurenbo/mixin_ar_base.rb +38 -15
- data/lib/kakurenbo/mixin_ar_relation.rb +82 -0
- data/lib/kakurenbo/version.rb +1 -1
- data/spec/kakurenbo/cores/associations_spec.rb +178 -0
- data/spec/kakurenbo/cores/callbacks_spec.rb +102 -0
- data/spec/kakurenbo/cores/core_spec.rb +186 -0
- data/spec/kakurenbo/cores/scopes_spec.rb +96 -0
- data/spec/kakurenbo/mixin_ar_base_spec.rb +65 -46
- data/spec/kakurenbo/mixin_ar_relation_spec.rb +117 -0
- data/spec/spec_helper.rb +15 -2
- metadata +19 -16
- data/spec/kakurenbo/soft_delete_cores/associations_spec.rb +0 -270
- data/spec/kakurenbo/soft_delete_cores/callbacks_spec.rb +0 -38
- data/spec/kakurenbo/soft_delete_cores/core_spec.rb +0 -229
- data/spec/kakurenbo/soft_delete_cores/scopes_spec.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0eed74f6f1f4ee3e648f8d23f196b017a3933a0
|
4
|
+
data.tar.gz: 9aba55b5f4d2191702e64feecfc348051fff0ad2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd0dc2d6abe2a70959bb5fdabcdf3b6970d24530208538c19af5e4d38f570f360a593a506f53ea867801f3bbb57a54ac005a45cdd711e973824888c4a2974e72
|
7
|
+
data.tar.gz: a0305a8d5be99ea68c939dbd8a3e279548b8cd39e87ee14fe6c1c017655e4e87a734695b19b6c890cf0efc4b5866a8ff45bf252cca1afb53500c5b63c10572ec
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Kakurenbo
|
2
2
|
|
3
3
|
Kakurenbo provides soft delete.
|
4
|
-
Kakurenbo is a re-implementation of [paranoia](http://github.com/radar/paranoia) and [acts\_as\_paranoid](http://github.com/technoweenie/acts_as_paranoid) for Rails4
|
4
|
+
Kakurenbo is a re-implementation of [paranoia](http://github.com/radar/paranoia) and [acts\_as\_paranoid](http://github.com/technoweenie/acts_as_paranoid) for Rails4. implemented a function that other gems are not enough.
|
5
5
|
|
6
6
|
The usage of the Kakurenbo is very very very simple. Only add `deleted_at`(datetime) to column.
|
7
7
|
Of course you can use `acts_as_paranoid`.In addition, Kakurenbo has many advantageous.
|
@@ -30,38 +30,50 @@ _Kakurenbo provides `acts_as_paranoid` method for compatibility._
|
|
30
30
|
### soft-delete
|
31
31
|
|
32
32
|
``` ruby
|
33
|
+
# if action is cancelled by callbacks, return false.
|
33
34
|
model.destroy
|
34
35
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
36
|
+
# if action is cancelled by callbacks, raise ActiveRecord::RecordNotDestroyed.
|
37
|
+
model.destroy!
|
38
|
+
|
39
|
+
# selected model will be destroyed.
|
40
|
+
Model.where(:foo => 'bar').destroy_all
|
38
41
|
```
|
39
42
|
|
40
43
|
when want without callbacks.
|
41
44
|
|
42
45
|
``` ruby
|
43
46
|
model.delete
|
47
|
+
|
48
|
+
# selected model will be deleted.
|
49
|
+
Model.where(:foo => 'bar').delete_all
|
44
50
|
```
|
45
51
|
|
46
52
|
### restore a record
|
47
53
|
|
48
54
|
``` ruby
|
49
|
-
|
55
|
+
# if action is cancelled by callbacks, return false.
|
56
|
+
model.restore
|
50
57
|
|
51
|
-
#
|
52
|
-
|
53
|
-
Model.restore([id1,id2,id3])
|
58
|
+
# if action is cancelled by callbacks, raise ActiveRecord::RecordNotRestored.
|
59
|
+
model.restore!
|
54
60
|
```
|
55
|
-
|
56
61
|
When restore, call restore callbacks.`before_restore` `after_restore`
|
57
62
|
|
58
63
|
|
59
64
|
### hard-delete
|
65
|
+
Use hard option.
|
66
|
+
``` ruby
|
67
|
+
model.destroy(hard: true)
|
60
68
|
|
69
|
+
# without callbacks.
|
70
|
+
model.delete(hard: true)
|
61
71
|
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
# selected model will be destroyed.
|
73
|
+
Model.where(:foo => 'bar').destroy_all(nil, hard: true)
|
74
|
+
|
75
|
+
# selected model will be destroyed.
|
76
|
+
Model.where(:foo => 'bar').delete_all(nil, hard: true)
|
65
77
|
```
|
66
78
|
|
67
79
|
### check if a record is fotdeleted
|
data/kakurenbo.gemspec
CHANGED
@@ -34,9 +34,9 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
spec.add_development_dependency "bundler", "~> 1.5"
|
36
36
|
spec.add_development_dependency "rake"
|
37
|
-
spec.add_development_dependency "rspec"
|
37
|
+
spec.add_development_dependency "rspec", ">= 3.0.0"
|
38
38
|
spec.add_development_dependency "yard"
|
39
39
|
spec.add_development_dependency "sqlite3"
|
40
40
|
|
41
|
-
spec.add_dependency 'activerecord', '>=
|
41
|
+
spec.add_dependency 'activerecord', '>= 4.0.2'
|
42
42
|
end
|
data/lib/kakurenbo.rb
CHANGED
@@ -5,7 +5,14 @@ require "active_record"
|
|
5
5
|
# require kakurenbo modules.
|
6
6
|
require "kakurenbo/version"
|
7
7
|
require "kakurenbo/mixin_ar_base"
|
8
|
-
require "kakurenbo/
|
8
|
+
require "kakurenbo/mixin_ar_relation"
|
9
|
+
require "kakurenbo/core"
|
10
|
+
|
11
|
+
# Kakurenbo Add ActiveRecord::RecordNotRestored to ActiveRecord
|
12
|
+
class ActiveRecord::RecordNotRestored < ActiveRecord::RecordNotDestroyed; end
|
9
13
|
|
10
14
|
# Kakurenbo Mixin to ActiveRecord::Base.
|
11
15
|
ActiveRecord::Base.send :include, Kakurenbo::MixinARBase
|
16
|
+
|
17
|
+
# Kakurenbo Mixin to ActiveRecord::Relation.
|
18
|
+
ActiveRecord::Relation.send :include, Kakurenbo::MixinARRelation
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Kakurenbo
|
2
|
-
module
|
2
|
+
module Core
|
3
3
|
# Extend ClassMethods after include.
|
4
4
|
def self.included(base_class)
|
5
5
|
base_class.extend ClassMethods
|
@@ -8,28 +8,13 @@ module Kakurenbo
|
|
8
8
|
base_class.extend Aliases
|
9
9
|
end
|
10
10
|
|
11
|
-
module
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# @param id [Array<Integer> or Integer] id or ids
|
19
|
-
def destroy(id)
|
20
|
-
transaction do
|
21
|
-
where(:id => id).each{|m| m.destroy}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Restore model(s).
|
26
|
-
#
|
27
|
-
# @param id [Array<Integer> or Integer] id or ids.
|
28
|
-
# @param options [Hash] options(same restore of instance methods.)
|
29
|
-
def restore(id, options = {:recursive => true})
|
30
|
-
transaction do
|
31
|
-
only_deleted.where(:id => id).each{|m| m.restore!(options)}
|
32
|
-
end
|
11
|
+
module Aliases
|
12
|
+
def self.extended(base_class)
|
13
|
+
base_class.instance_eval {
|
14
|
+
alias_method :deleted?, :destroyed?
|
15
|
+
alias_method :recover, :restore
|
16
|
+
alias_method :recover!, :restore!
|
17
|
+
}
|
33
18
|
end
|
34
19
|
end
|
35
20
|
|
@@ -41,51 +26,76 @@ module Kakurenbo
|
|
41
26
|
set_callback(:restore, on, *args, &block)
|
42
27
|
end
|
43
28
|
end
|
44
|
-
base_class.
|
29
|
+
base_class.define_model_callbacks :restore
|
45
30
|
end
|
46
31
|
end
|
47
32
|
|
33
|
+
module ClassMethods
|
34
|
+
def paranoid?; true end
|
35
|
+
end
|
36
|
+
|
48
37
|
module Scopes
|
49
38
|
def self.extended(base_class)
|
50
39
|
base_class.instance_eval {
|
51
40
|
scope :only_deleted, ->{ with_deleted.where.not( kakurenbo_column => nil ) }
|
52
|
-
scope :with_deleted, ->{ all.tap{ |s| s.default_scoped = false } }
|
53
41
|
scope :without_deleted, ->{ where(kakurenbo_column => nil) }
|
42
|
+
if ActiveRecord::VERSION::STRING >= "4.1"
|
43
|
+
scope :with_deleted, ->{ unscope :where => kakurenbo_column }
|
44
|
+
else
|
45
|
+
scope :with_deleted, ->{ all.tap{ |s| s.default_scoped = false } }
|
46
|
+
end
|
54
47
|
|
55
48
|
default_scope ->{ without_deleted }
|
56
49
|
}
|
57
50
|
end
|
58
51
|
end
|
59
52
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
53
|
+
# delete record.
|
54
|
+
#
|
55
|
+
# @param options [Hash] options.
|
56
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
57
|
+
def delete(options = {:hard => false})
|
58
|
+
if options[:hard]
|
59
|
+
self.class.delete(self.id, options)
|
60
|
+
else
|
61
|
+
return if new_record? or destroyed?
|
62
|
+
update_column kakurenbo_column, current_time_from_proper_timezone
|
68
63
|
end
|
69
64
|
end
|
70
65
|
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
# destroy record and run callbacks.
|
67
|
+
#
|
68
|
+
# @param options [Hash] options.
|
69
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
70
|
+
#
|
71
|
+
# @return [Boolean, self] if action is cancelled, return false.
|
72
|
+
def destroy(options = {:hard => false})
|
73
|
+
if options[:hard]
|
74
|
+
with_transaction_returning_status do
|
75
|
+
hard_destroy_associated_records
|
76
|
+
self.reload.hard_destroy
|
77
|
+
end
|
78
|
+
else
|
79
|
+
return true if destroyed?
|
80
|
+
with_transaction_returning_status do
|
81
|
+
destroy_at = current_time_from_proper_timezone
|
82
|
+
run_callbacks(:destroy){ update_column kakurenbo_column, destroy_at; self }
|
83
|
+
end
|
84
|
+
end
|
74
85
|
end
|
75
86
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
87
|
+
# destroy record and run callbacks.
|
88
|
+
#
|
89
|
+
# @param options [Hash] options.
|
90
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
91
|
+
#
|
92
|
+
# @return [self] self.
|
93
|
+
def destroy!(options = {:hard => false})
|
94
|
+
destroy(options) || raise(ActiveRecord::RecordNotDestroyed)
|
82
95
|
end
|
83
96
|
|
84
|
-
def
|
85
|
-
|
86
|
-
hard_destroy_associated_records
|
87
|
-
self.reload.hard_destroy!
|
88
|
-
end
|
97
|
+
def destroy_row
|
98
|
+
relation_for_destroy.delete_all(nil, :hard => true)
|
89
99
|
end
|
90
100
|
|
91
101
|
def destroyed?
|
@@ -103,19 +113,32 @@ module Kakurenbo
|
|
103
113
|
# restore record.
|
104
114
|
#
|
105
115
|
# @param options [Hash] options.
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
def restore
|
116
|
+
# @option options [Boolean] recursive (true) if restore recursive.
|
117
|
+
#
|
118
|
+
# @return [Boolean, self] if action is cancelled, return false.
|
119
|
+
def restore(options = {:recursive => true})
|
120
|
+
return false unless destroyed?
|
121
|
+
|
110
122
|
with_transaction_returning_status do
|
111
123
|
run_callbacks(:restore) do
|
112
124
|
parent_deleted_at = send(kakurenbo_column)
|
113
|
-
update_column kakurenbo_column, nil
|
114
125
|
restore_associated_records(parent_deleted_at) if options[:recursive]
|
126
|
+
update_column kakurenbo_column, nil
|
127
|
+
self
|
115
128
|
end
|
116
129
|
end
|
117
130
|
end
|
118
131
|
|
132
|
+
# restore record.
|
133
|
+
#
|
134
|
+
# @param options [Hash] options.
|
135
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
136
|
+
#
|
137
|
+
# @return [self] self.
|
138
|
+
def restore!(options = {:recursive => true})
|
139
|
+
restore(options) || raise(ActiveRecord::RecordNotRestored)
|
140
|
+
end
|
141
|
+
|
119
142
|
private
|
120
143
|
# get recoreds of association.
|
121
144
|
#
|
@@ -148,7 +171,7 @@ module Kakurenbo
|
|
148
171
|
# Hard-Destroy associated records.
|
149
172
|
def hard_destroy_associated_records
|
150
173
|
each_dependent_destroy_records do |record|
|
151
|
-
record.destroy
|
174
|
+
record.destroy(hard: true)
|
152
175
|
end
|
153
176
|
end
|
154
177
|
|
@@ -6,31 +6,60 @@ module Kakurenbo
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
+
delegate :restore, :restore_all, {:to => :with_deleted}
|
10
|
+
|
9
11
|
# Initialize Kakurenbo in child class.
|
10
12
|
def inherited(child_class)
|
13
|
+
super
|
14
|
+
|
15
|
+
child_class.define_singleton_method :table_name= do |value|
|
16
|
+
super(value)
|
17
|
+
if has_kakurenbo_column?
|
18
|
+
remodel_as_soft_delete
|
19
|
+
else
|
20
|
+
remodel_as_original
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
11
24
|
child_class.instance_eval do
|
12
25
|
remodel_as_soft_delete if has_kakurenbo_column?
|
13
26
|
end
|
14
|
-
|
27
|
+
end
|
28
|
+
|
29
|
+
# Remodel Model as normal.
|
30
|
+
# @note Restore to original model.
|
31
|
+
def remodel_as_original
|
32
|
+
if paranoid?
|
33
|
+
alias_method :delete, :hard_delete
|
34
|
+
alias_method :destroy, :hard_destroy
|
35
|
+
alias_method :destroy!, :hard_destroy!
|
36
|
+
|
37
|
+
singleton_class.send(:alias_method, :delete, :hard_delete)
|
38
|
+
singleton_class.send(:alias_method, :delete_all, :hard_delete_all)
|
39
|
+
|
40
|
+
define_singleton_method(:paranoid?) { false }
|
41
|
+
end
|
15
42
|
end
|
16
43
|
|
17
44
|
# Remodel Model as soft-delete.
|
18
45
|
#
|
19
|
-
# @
|
20
|
-
#
|
21
|
-
# :column => :deleted_at
|
22
|
-
# }
|
46
|
+
# @params option [Hash] option.
|
47
|
+
# @option option [Symbol] column column of kakurenbo.
|
23
48
|
def remodel_as_soft_delete(options = {})
|
24
49
|
options.reverse_merge!(
|
25
50
|
:column => :deleted_at
|
26
51
|
)
|
27
52
|
|
28
53
|
unless paranoid?
|
29
|
-
alias_method :hard_delete
|
30
|
-
alias_method :hard_destroy
|
54
|
+
alias_method :hard_delete, :delete
|
55
|
+
alias_method :hard_destroy, :destroy
|
56
|
+
alias_method :hard_destroy!, :destroy!
|
57
|
+
|
58
|
+
singleton_class.send(:alias_method, :hard_delete, :delete)
|
59
|
+
singleton_class.send(:alias_method, :hard_delete_all, :delete_all)
|
31
60
|
|
32
61
|
class_attribute :kakurenbo_column
|
33
|
-
include Kakurenbo::
|
62
|
+
include Kakurenbo::Core
|
34
63
|
end
|
35
64
|
|
36
65
|
self.kakurenbo_column = options[:column]
|
@@ -42,19 +71,13 @@ module Kakurenbo
|
|
42
71
|
false
|
43
72
|
end
|
44
73
|
|
45
|
-
# When set table name, remodel.
|
46
|
-
def table_name=(value)
|
47
|
-
super
|
48
|
-
remodel_as_soft_delete if has_kakurenbo_column?
|
49
|
-
end
|
50
|
-
|
51
74
|
private
|
52
75
|
# Check if Model has kakurenbo_column.
|
53
76
|
#
|
54
77
|
# @return [Boolean] result.
|
55
78
|
def has_kakurenbo_column?
|
56
79
|
begin
|
57
|
-
column_names.include?('deleted_at')
|
80
|
+
table_exists? and column_names.include?('deleted_at')
|
58
81
|
rescue
|
59
82
|
false
|
60
83
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Kakurenbo
|
2
|
+
module MixinARRelation
|
3
|
+
# Extend ClassMethods after include.
|
4
|
+
def self.included(base_class)
|
5
|
+
base_class.class_eval do
|
6
|
+
alias_method :hard_delete_all, :delete_all
|
7
|
+
|
8
|
+
# delete selected id or ids.
|
9
|
+
#
|
10
|
+
# @param id [Integer, Array<Integer>] ID or IDs.
|
11
|
+
# @param options [Hash] options.
|
12
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
13
|
+
def delete(id, options = {:hard => false})
|
14
|
+
delete_all({:id => id}, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# delete all record.
|
18
|
+
#
|
19
|
+
# @param conditions [Object] conditions.
|
20
|
+
# @param options [Hash] options.
|
21
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
22
|
+
def delete_all(conditions = nil, options = {:hard => false})
|
23
|
+
return hard_delete_all(conditions) unless klass.paranoid?
|
24
|
+
|
25
|
+
if conditions
|
26
|
+
where(conditions).delete_all(nil, options)
|
27
|
+
else
|
28
|
+
if options[:hard]
|
29
|
+
hard_delete_all
|
30
|
+
else
|
31
|
+
update_all({ klass.kakurenbo_column => Time.now })
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# destroy selected id or ids.
|
37
|
+
#
|
38
|
+
# @param id [Integer, Array<Integer>] ID or IDs.
|
39
|
+
# @param options [Hash] options.
|
40
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
41
|
+
def destroy(id, options = {:hard => false})
|
42
|
+
destroy_all({:id => id}, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
# destroy all record.
|
46
|
+
#
|
47
|
+
# @param conditions [Object] conditions.
|
48
|
+
# @param options [Hash] options.
|
49
|
+
# @option options [Boolean] hard (false) if hard-delete.
|
50
|
+
def destroy_all(conditions = nil, options = {:hard => false})
|
51
|
+
if conditions
|
52
|
+
where(conditions).destroy_all(nil, options)
|
53
|
+
else
|
54
|
+
to_a.each {|object| object.destroy(options) }.tap { reset }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# restore selected id or ids.
|
59
|
+
#
|
60
|
+
# @param id [Integer, Array<Integer>] ID or IDs.
|
61
|
+
# @param options [Hash] options.
|
62
|
+
# @option options [Boolean] recursive (true) if restore recursive.
|
63
|
+
def restore(id, options = {:recursive => true})
|
64
|
+
restore_all({:id => id}, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
# restore all record.
|
68
|
+
#
|
69
|
+
# @param conditions [Object] conditions.
|
70
|
+
# @param options [Hash] options.
|
71
|
+
# @option options [Boolean] recursive (true) if restore recursive.
|
72
|
+
def restore_all(conditions = nil, options = {:recursive => true})
|
73
|
+
if conditions
|
74
|
+
where(conditions).restore_all(nil, options)
|
75
|
+
else
|
76
|
+
to_a.each {|object| object.restore(options) }.tap { reset }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|