permanent_records 4.1.0 → 4.1.1
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 +1 -0
- data/Rakefile +13 -6
- data/VERSION +1 -1
- data/ci +1 -1
- data/lib/permanent_records.rb +126 -85
- data/permanent_records.gemspec +21 -14
- metadata +34 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fc77ef2eb0c9943d477c2bb228a11d31c1fd0a7
|
4
|
+
data.tar.gz: 748645f6c54d8f067c20c494ed451d9cdccaffd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c72d7ef29d6a675e511d67194a265c6b2b183a7d629deed3fc63b9e911a75dbd8b59c2a7e57c81cd15d9c12af6a8f4a6115b9fe5b6cbf059139c3ee8465c7dcf
|
7
|
+
data.tar.gz: 925ce8fe43fae831d5bd73291bce29d9d0d6747c89d6a08e2d2b49239b27c328352576c73a4f3afb4c1bdae82974ba955a94fe3e7ee9c3e6d262c23eaa0421f8
|
data/.travis.yml
CHANGED
data/Rakefile
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
require 'yaml'
|
3
|
+
require 'English'
|
3
4
|
Bundler::GemHelper.install_tasks
|
4
5
|
|
5
|
-
|
6
|
+
CONFIG = YAML.load_file(
|
7
|
+
File.expand_path('spec/support/database.yml', File.dirname(__FILE__))
|
8
|
+
)
|
6
9
|
|
7
10
|
def test_database_exists?
|
8
|
-
system "psql -l | grep -q #{
|
9
|
-
|
11
|
+
system "psql -l | grep -q #{CONFIG['test'][:database]}"
|
12
|
+
$CHILD_STATUS.success?
|
10
13
|
end
|
11
14
|
|
12
15
|
def create_test_database
|
13
|
-
system "createdb #{
|
16
|
+
system "createdb #{CONFIG['test'][:database]}"
|
14
17
|
end
|
15
18
|
|
16
19
|
namespace :db do
|
@@ -19,9 +22,13 @@ namespace :db do
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
|
25
|
+
require 'rubocop/rake_task'
|
26
|
+
RuboCop::RakeTask.new
|
23
27
|
|
24
28
|
desc 'Run all tests'
|
25
|
-
task :
|
29
|
+
task spec: 'db:create' do
|
26
30
|
exec 'rspec'
|
27
31
|
end
|
32
|
+
|
33
|
+
task default: [:spec, :rubocop]
|
34
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.1.
|
1
|
+
4.1.1
|
data/ci
CHANGED
data/lib/permanent_records.rb
CHANGED
@@ -1,40 +1,47 @@
|
|
1
|
+
# PermanentRecords works with ActiveRecord to set deleted_at columns with a
|
2
|
+
# timestamp reflecting when a record was 'deleted' instead of actually deleting
|
3
|
+
# the record. All dependent records and associations are treated exactly as
|
4
|
+
# you'd expect: If there's a deleted_at column then the record is preserved,
|
5
|
+
# otherwise it's deleted.
|
1
6
|
module PermanentRecords
|
2
|
-
|
3
7
|
# This module defines the public api that you can
|
4
8
|
# use in your model instances.
|
5
9
|
#
|
6
10
|
# * is_permanent? #=> true/false, depending if you have a deleted_at column
|
7
11
|
# * deleted? #=> true/false, depending if you've called .destroy
|
8
|
-
# * destroy #=> sets deleted_at, your record is now in
|
12
|
+
# * destroy #=> sets deleted_at, your record is now in
|
13
|
+
# the .destroyed scope
|
9
14
|
# * revive #=> undo the destroy
|
10
|
-
module ActiveRecord
|
15
|
+
module ActiveRecord # rubocop:disable Metrics/ModuleLength
|
11
16
|
def self.included(base)
|
12
|
-
|
13
17
|
base.extend Scopes
|
14
18
|
base.extend IsPermanent
|
15
19
|
|
16
20
|
base.instance_eval do
|
17
21
|
define_model_callbacks :revive
|
18
|
-
|
19
|
-
before_revive :revive_destroyed_dependent_records
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
def is_permanent?
|
25
|
+
def is_permanent? # rubocop:disable Style/PredicateName
|
24
26
|
respond_to?(:deleted_at)
|
25
27
|
end
|
26
28
|
|
27
29
|
def deleted?
|
28
30
|
if is_permanent?
|
29
|
-
!!deleted_at
|
31
|
+
!!deleted_at # rubocop:disable Style/DoubleNegation
|
30
32
|
else
|
31
33
|
destroyed?
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
def revive(
|
37
|
+
def revive(options = nil)
|
36
38
|
with_transaction_returning_status do
|
37
|
-
|
39
|
+
if PermanentRecords.should_revive_parent_first?(options)
|
40
|
+
revival.reverse
|
41
|
+
else
|
42
|
+
revival
|
43
|
+
end.each { |p| p.call(options) }
|
44
|
+
|
38
45
|
self
|
39
46
|
end
|
40
47
|
end
|
@@ -51,23 +58,46 @@ module PermanentRecords
|
|
51
58
|
|
52
59
|
private
|
53
60
|
|
61
|
+
def revival
|
62
|
+
[
|
63
|
+
lambda do |validate|
|
64
|
+
revive_destroyed_dependent_records(validate)
|
65
|
+
end,
|
66
|
+
lambda do |validate|
|
67
|
+
run_callbacks(:revive) { set_deleted_at(nil, validate) }
|
68
|
+
end
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
# rubocop:disable Style/AccessorMethodName
|
73
|
+
def get_deleted_record
|
74
|
+
# Looking for parent on STI case
|
75
|
+
if respond_to?(:parent_id) && parent_id.present?
|
76
|
+
self.class.unscoped.find(parent_id)
|
77
|
+
else
|
78
|
+
self.class.unscoped.find(id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# rubocop:disable Metrics/MethodLength
|
54
83
|
def set_deleted_at(value, force = nil)
|
55
84
|
return self unless is_permanent?
|
56
|
-
record =
|
85
|
+
record = get_deleted_record
|
57
86
|
record.deleted_at = value
|
58
87
|
begin
|
59
|
-
# we call save! instead of update_attribute so an
|
60
|
-
# error will be raised if the record isn't
|
61
|
-
# disregard validation
|
88
|
+
# we call save! instead of update_attribute so an
|
89
|
+
# ActiveRecord::RecordInvalid error will be raised if the record isn't
|
90
|
+
# valid. (This prevents reviving records that disregard validation
|
91
|
+
# constraints,)
|
62
92
|
if PermanentRecords.should_ignore_validations?(force)
|
63
|
-
record.save(:
|
93
|
+
record.save(validate: false)
|
64
94
|
else
|
65
95
|
record.save!
|
66
96
|
end
|
67
97
|
@attributes = record.instance_variable_get('@attributes')
|
68
|
-
rescue
|
69
|
-
# trigger dependent record destruction (they were revived before this
|
70
|
-
# which cannot be revived due to validations)
|
98
|
+
rescue => e
|
99
|
+
# trigger dependent record destruction (they were revived before this
|
100
|
+
# record, which cannot be revived due to validations)
|
71
101
|
record.destroy
|
72
102
|
raise e
|
73
103
|
end
|
@@ -81,28 +111,36 @@ module PermanentRecords
|
|
81
111
|
deleted? ? self : false
|
82
112
|
end
|
83
113
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
114
|
+
def add_record_window(_request, name, reflection)
|
115
|
+
send(name).unscope(where: :deleted_at).where(
|
116
|
+
[
|
117
|
+
"#{reflection.quoted_table_name}.deleted_at > ?" \
|
118
|
+
' AND ' \
|
119
|
+
"#{reflection.quoted_table_name}.deleted_at < ?",
|
120
|
+
deleted_at - PermanentRecords.dependent_record_window,
|
121
|
+
deleted_at + PermanentRecords.dependent_record_window
|
122
|
+
]
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
# TODO: Feel free to refactor this without polluting the ActiveRecord
|
127
|
+
# namespace.
|
128
|
+
# rubocop:disable Metrics/AbcSize
|
129
|
+
def revive_destroyed_dependent_records(force = nil)
|
130
|
+
PermanentRecords.dependent_permanent_reflections(self.class)
|
131
|
+
.each do |name, reflection|
|
132
|
+
cardinality = reflection.macro.to_s.gsub('has_', '').to_sym
|
133
|
+
case cardinality
|
134
|
+
when :many
|
135
|
+
if deleted_at
|
136
|
+
add_record_window(send(name), name, reflection)
|
137
|
+
else
|
138
|
+
send(name)
|
102
139
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
140
|
+
when :one, :belongs_to
|
141
|
+
self.class.unscoped { Array(send(name)) }
|
142
|
+
end.to_a.flatten.compact.each do |dependent|
|
143
|
+
dependent.revive(force)
|
106
144
|
end
|
107
145
|
|
108
146
|
# and update the reflection cache
|
@@ -111,46 +149,34 @@ module PermanentRecords
|
|
111
149
|
end
|
112
150
|
|
113
151
|
def attempt_notifying_observers(callback)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
# do nothing: this model isn't being observed
|
118
|
-
end
|
152
|
+
notify_observers(callback)
|
153
|
+
rescue NoMethodError # rubocop:disable Lint/HandleExceptions
|
154
|
+
# do nothing: this model isn't being observed
|
119
155
|
end
|
120
156
|
|
121
|
-
# return the records corresponding to an association with the `:dependent
|
122
|
-
|
123
|
-
|
124
|
-
|
157
|
+
# return the records corresponding to an association with the `:dependent
|
158
|
+
# => :destroy` option
|
159
|
+
def dependent_record_ids
|
125
160
|
# check which dependent records are to be destroyed
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
next unless records.size > 0 # skip if there are no dependent record instances
|
132
|
-
else
|
133
|
-
records = [] << records
|
134
|
-
end
|
135
|
-
dependent_record = records.first
|
136
|
-
next if dependent_record.nil?
|
137
|
-
dependent_records[dependent_record.class] = records.map(&:id)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
dependent_records
|
141
|
-
end
|
142
|
-
|
143
|
-
# If we force the destruction of the record, we will need to force the destruction of dependent records if the
|
144
|
-
# user specified `:dependent => :destroy` in the model.
|
145
|
-
# By default, the call to super/destroy_with_permanent_records (i.e. the &block param) will only soft delete
|
146
|
-
# the dependent records; we keep track of the dependent records
|
147
|
-
# that have `:dependent => :destroy` and call destroy(force) on them after the call to super
|
148
|
-
def permanently_delete_records_after(&block)
|
149
|
-
dependent_records = get_dependent_records
|
150
|
-
result = block.call
|
151
|
-
if result
|
152
|
-
permanently_delete_records(dependent_records)
|
161
|
+
PermanentRecords.dependent_reflections(self.class)
|
162
|
+
.reduce({}) do |records, (key, _)|
|
163
|
+
found = Array(send(key)).compact
|
164
|
+
next records unless found.size > 0
|
165
|
+
records.update found.first.class => found.map(&:id)
|
153
166
|
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# If we force the destruction of the record, we will need to force the
|
170
|
+
# destruction of dependent records if the user specified `:dependent =>
|
171
|
+
# :destroy` in the model. By default, the call to
|
172
|
+
# super/destroy_with_permanent_records (i.e. the &block param) will only
|
173
|
+
# soft delete the dependent records; we keep track of the dependent records
|
174
|
+
# that have `:dependent => :destroy` and call destroy(force) on them after
|
175
|
+
# the call to super
|
176
|
+
def permanently_delete_records_after(&_block)
|
177
|
+
dependent_records = dependent_record_ids
|
178
|
+
result = yield
|
179
|
+
permanently_delete_records(dependent_records) if result
|
154
180
|
result
|
155
181
|
end
|
156
182
|
|
@@ -158,11 +184,8 @@ module PermanentRecords
|
|
158
184
|
def permanently_delete_records(dependent_records)
|
159
185
|
dependent_records.each do |klass, ids|
|
160
186
|
ids.each do |id|
|
161
|
-
record =
|
162
|
-
|
163
|
-
rescue ::ActiveRecord::RecordNotFound
|
164
|
-
next # the record has already been deleted, possibly due to another association with `:dependent => :destroy`
|
165
|
-
end
|
187
|
+
record = klass.unscoped.where(klass.primary_key => id).first
|
188
|
+
next unless record
|
166
189
|
record.deleted_at = nil
|
167
190
|
record.destroy(:force)
|
168
191
|
end
|
@@ -170,6 +193,7 @@ module PermanentRecords
|
|
170
193
|
end
|
171
194
|
end
|
172
195
|
|
196
|
+
# ActiveRelation scopes
|
173
197
|
module Scopes
|
174
198
|
def deleted
|
175
199
|
where arel_table[:deleted_at].not_eq(nil)
|
@@ -180,22 +204,27 @@ module PermanentRecords
|
|
180
204
|
end
|
181
205
|
end
|
182
206
|
|
207
|
+
# Included into ActiveRecord for all models
|
183
208
|
module IsPermanent
|
184
|
-
def is_permanent?
|
185
|
-
columns.detect {|c| 'deleted_at' == c.name}
|
209
|
+
def is_permanent? # rubocop:disable Style/PredicateName
|
210
|
+
columns.detect { |c| 'deleted_at' == c.name }
|
186
211
|
end
|
187
212
|
end
|
188
213
|
|
189
214
|
def self.should_force_destroy?(force)
|
190
|
-
if Hash
|
215
|
+
if force.is_a?(Hash)
|
191
216
|
force[:force]
|
192
217
|
else
|
193
218
|
:force == force
|
194
219
|
end
|
195
220
|
end
|
196
221
|
|
222
|
+
def self.should_revive_parent_first?(order)
|
223
|
+
order.is_a?(Hash) && true == order[:reverse]
|
224
|
+
end
|
225
|
+
|
197
226
|
def self.should_ignore_validations?(force)
|
198
|
-
Hash
|
227
|
+
force.is_a?(Hash) && false == force[:validate]
|
199
228
|
end
|
200
229
|
|
201
230
|
def self.dependent_record_window
|
@@ -205,7 +234,19 @@ module PermanentRecords
|
|
205
234
|
def self.dependent_record_window=(time_value)
|
206
235
|
@dependent_record_window = time_value
|
207
236
|
end
|
237
|
+
|
238
|
+
def self.dependent_reflections(klass)
|
239
|
+
klass.reflections.select do |_, reflection|
|
240
|
+
# skip if there are no dependent record instances
|
241
|
+
reflection.options[:dependent] == :destroy
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.dependent_permanent_reflections(klass)
|
246
|
+
dependent_reflections(klass).select do |_name, reflection|
|
247
|
+
reflection.klass.is_permanent?
|
248
|
+
end
|
249
|
+
end
|
208
250
|
end
|
209
251
|
|
210
252
|
ActiveRecord::Base.send :include, PermanentRecords::ActiveRecord
|
211
|
-
|
data/permanent_records.gemspec
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
Gem::Specification.new do |s|
|
3
|
-
s.name =
|
3
|
+
s.name = 'permanent_records'
|
4
4
|
s.version = File.read('VERSION')
|
5
5
|
s.license = 'MIT'
|
6
6
|
|
7
|
-
s.authors = [
|
8
|
-
|
9
|
-
|
10
|
-
s.
|
7
|
+
s.authors = ['Jack Danger Canty', 'David Sulc', 'Joe Nelson',
|
8
|
+
'Trond Arve Nordheim', 'Josh Teneycke', 'Maximilian Herold',
|
9
|
+
'Hugh Evans']
|
10
|
+
s.summary = 'Soft-delete your ActiveRecord records'
|
11
|
+
s.description = <<-EOS
|
12
|
+
Never Lose Data. Rather than deleting rows this sets Record#deleted_at and
|
13
|
+
gives you all the scopes you need to work with your data.
|
14
|
+
EOS
|
15
|
+
s.email = 'github@jackcanty.com'
|
11
16
|
s.extra_rdoc_files = [
|
12
|
-
|
13
|
-
|
17
|
+
'LICENSE',
|
18
|
+
'README.md'
|
14
19
|
]
|
15
|
-
s.files = `git ls-files -z`.split("\x0").reject
|
16
|
-
|
17
|
-
|
20
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
f.match(%r{^(test|spec|features)/})
|
22
|
+
end
|
23
|
+
s.homepage = 'https://github.com/JackDanger/permanent_records'
|
24
|
+
s.require_paths = ['lib']
|
18
25
|
|
19
26
|
# For testing against multiple AR versions
|
20
27
|
ver = ENV['AR_TEST_VERSION']
|
@@ -22,10 +29,10 @@ Gem::Specification.new do |s|
|
|
22
29
|
|
23
30
|
s.add_runtime_dependency('activerecord', ver || '>= 4.2.0')
|
24
31
|
s.add_runtime_dependency('activesupport', ver || '>= 4.2.0')
|
25
|
-
s.add_development_dependency('rake') # For Travis-ci
|
26
|
-
s.add_development_dependency('sqlite3')
|
27
|
-
s.add_development_dependency('pry-byebug')
|
28
32
|
s.add_development_dependency('database_cleaner', '>= 1.5.1')
|
33
|
+
s.add_development_dependency('pry-byebug')
|
34
|
+
s.add_development_dependency('rake') # For Travis-ci
|
29
35
|
s.add_development_dependency('rspec', '~> 2.14.1')
|
36
|
+
s.add_development_dependency('rubocop')
|
37
|
+
s.add_development_dependency('sqlite3')
|
30
38
|
end
|
31
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: permanent_records
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.1.
|
4
|
+
version: 4.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Danger Canty
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date:
|
17
|
+
date: 2016-02-02 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: activerecord
|
@@ -45,21 +45,21 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 4.2.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: database_cleaner
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 1.5.1
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 1.5.1
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
62
|
+
name: pry-byebug
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
@@ -73,7 +73,7 @@ dependencies:
|
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
76
|
+
name: rake
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - ">="
|
@@ -87,35 +87,50 @@ dependencies:
|
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.14.1
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.14.1
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: rubocop
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - ">="
|
94
108
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
109
|
+
version: '0'
|
96
110
|
type: :development
|
97
111
|
prerelease: false
|
98
112
|
version_requirements: !ruby/object:Gem::Requirement
|
99
113
|
requirements:
|
100
114
|
- - ">="
|
101
115
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
116
|
+
version: '0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
118
|
+
name: sqlite3
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
106
120
|
requirements:
|
107
|
-
- - "
|
121
|
+
- - ">="
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
123
|
+
version: '0'
|
110
124
|
type: :development
|
111
125
|
prerelease: false
|
112
126
|
version_requirements: !ruby/object:Gem::Requirement
|
113
127
|
requirements:
|
114
|
-
- - "
|
128
|
+
- - ">="
|
115
129
|
- !ruby/object:Gem::Version
|
116
|
-
version:
|
117
|
-
description:
|
118
|
-
|
130
|
+
version: '0'
|
131
|
+
description: |
|
132
|
+
Never Lose Data. Rather than deleting rows this sets Record#deleted_at and
|
133
|
+
gives you all the scopes you need to work with your data.
|
119
134
|
email: github@jackcanty.com
|
120
135
|
executables: []
|
121
136
|
extensions: []
|
@@ -155,8 +170,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
170
|
version: '0'
|
156
171
|
requirements: []
|
157
172
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.5.1
|
159
174
|
signing_key:
|
160
175
|
specification_version: 4
|
161
176
|
summary: Soft-delete your ActiveRecord records
|
162
177
|
test_files: []
|
178
|
+
has_rdoc:
|