active_archive 5.1.7 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02ef56cf163f46d646a5c33c14aaad6597e413faf018434af73e70293ea7bb9a
4
- data.tar.gz: 46d27202b989f81bb8a9bf587d0bd4f6ef701daf18787f2521e6aa0647bfb4e6
3
+ metadata.gz: 7ad44438d97ef3a4c739a8aabb9f9d61429743b9b2835007fdeed270fcf348b6
4
+ data.tar.gz: bb7a6181c2c98a989f5bcbc5465686bde9d0126a5f615c315516d8b005b6046f
5
5
  SHA512:
6
- metadata.gz: a9e6151c972359cca2d7e98ae5e994804905cf0c591554bfae87053cd614e24dfaa75c0081280b62c57d861053cd320126e7b68eb1c7eec6a282412cf1fc86a6
7
- data.tar.gz: d40636590b9f9df38dadc4ce971c15d29c5d7b1bf4a7a5817012b2dd757b4153cff8750238a68a2ab2dea92774e44c2d47a2e5cf35f8ec0803dcaf8837e30d66
6
+ metadata.gz: 893d7bdf1ba645e69c335e99a8b6127b36401d6013bca9ca7f35ea0124177de2dccc78378cd1eb4c57848cd91926ea659dd3db56430906d686a4b41fed50fad9
7
+ data.tar.gz: dab93ef545dcbc4f86f71442d7b2f91ddf05f533adf3c01ee993574382e782c51a44e27faab88b536627006f39c399d2c15dfce72fdd3bf96f5e2c363d9df4af
data/.reek.yml ADDED
@@ -0,0 +1,27 @@
1
+ ---
2
+ detectors:
3
+ Attribute:
4
+ enabled: false
5
+ DuplicateMethodCall:
6
+ enabled: false
7
+ FeatureEnvy:
8
+ enabled: false
9
+ IrresponsibleModule:
10
+ enabled: false
11
+ ManualDispatch:
12
+ enabled: false
13
+ NestedIterators:
14
+ max_allowed_nesting: 2
15
+ NilCheck:
16
+ enabled: false
17
+ TooManyStatements:
18
+ max_statements: 10
19
+ exclude:
20
+ - 'ActiveArchive::Base#retrieve_dependent_records'
21
+ - 'ActiveArchive::Base#set_archived_at'
22
+ UncommunicativeParameterName:
23
+ enabled: false
24
+ UncommunicativeVariableName:
25
+ enabled: false
26
+ UtilityFunction:
27
+ enabled: false
data/.rubocop.yml CHANGED
@@ -12,7 +12,7 @@ Layout/EmptyLinesAroundModuleBody:
12
12
  Enabled: false
13
13
  LineLength:
14
14
  Max: 100
15
- Lint/RescueWithoutErrorClass:
15
+ Lint/HandleExceptions:
16
16
  Enabled: false
17
17
  Lint/ScriptPermission:
18
18
  Enabled: false
@@ -20,7 +20,13 @@ Metrics/MethodLength:
20
20
  Enabled: false
21
21
  Metrics/ModuleLength:
22
22
  Enabled: false
23
+ Naming/AccessorMethodName:
24
+ Enabled: false
23
25
  Style/Alias:
24
26
  EnforcedStyle: prefer_alias_method
25
27
  Style/Documentation:
26
28
  Enabled: false
29
+ Style/ExpandPathArguments:
30
+ Enabled: false
31
+ Style/RescueStandardError:
32
+ Enabled: false
data/README.md CHANGED
@@ -43,12 +43,17 @@ end
43
43
 
44
44
  **Options:**
45
45
  * `archive`
46
+ * `archive_all`
47
+ * `archive_all!`
46
48
  * `destroy`
47
49
  * `destroy_all`
50
+ * `destroy_all!`
48
51
  * `delete`
49
52
  * `delete_all`
50
53
  * `unarchive`
51
54
  * `unarchive_all`
55
+ * `undestroy`
56
+ * `undestroy_all`
52
57
 
53
58
  ```ruby
54
59
  User.first.archive #=> archives User record and dependents
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # coding: utf-8
4
-
5
3
  lib = File.expand_path('../lib', __FILE__)
6
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
5
  require 'active_archive/version'
@@ -24,12 +22,12 @@ Gem::Specification.new do |spec|
24
22
  spec.add_runtime_dependency 'rails'
25
23
 
26
24
  spec.add_development_dependency 'bundler'
27
- spec.add_development_dependency 'rake'
28
- spec.add_development_dependency 'rspec'
29
- spec.add_development_dependency 'sqlite3'
30
25
  spec.add_development_dependency 'database_cleaner'
31
- spec.add_development_dependency 'generator_spec'
32
26
  spec.add_development_dependency 'fasterer'
27
+ spec.add_development_dependency 'generator_spec'
28
+ spec.add_development_dependency 'rake'
33
29
  spec.add_development_dependency 'reek'
30
+ spec.add_development_dependency 'rspec'
34
31
  spec.add_development_dependency 'rubocop'
32
+ spec.add_development_dependency 'sqlite3'
35
33
  end
@@ -10,14 +10,33 @@ module ActiveArchive
10
10
  base.instance_eval { define_model_callbacks(:unarchive) }
11
11
  end
12
12
 
13
+ def archivable?
14
+ respond_to?(:archived_at)
15
+ end
16
+
13
17
  def archived?
14
18
  archivable? ? !archived_at.nil? : destroyed?
15
19
  end
16
20
 
17
- def archivable?
18
- respond_to?(:archived_at)
21
+ def unarchived?
22
+ !archived?
23
+ end
24
+
25
+ def unarchivable?
26
+ !archivable?
27
+ end
28
+
29
+ def unarchive(opts = nil)
30
+ with_transaction_returning_status do
31
+ records = should_unarchive_parent_first?(opts) ? unarchival.reverse : unarchival
32
+ records.each { |rec| rec.call(opts) }
33
+
34
+ self
35
+ end
19
36
  end
20
37
 
38
+ alias_method :undestroy, :unarchive
39
+
21
40
  def destroy(force = nil)
22
41
  with_transaction_returning_status do
23
42
  if unarchivable? || should_force_destroy?(force)
@@ -28,36 +47,62 @@ module ActiveArchive
28
47
  end
29
48
  end
30
49
 
31
- alias_method(:archive, :destroy)
32
- alias_method(:archive!, :destroy)
50
+ alias_method :archive, :destroy
33
51
 
34
52
  def to_archival
35
53
  I18n.t("active_archive.archival.#{archived? ? :archived : :unarchived}")
36
54
  end
37
55
 
38
- def unarchive(opts = nil)
39
- with_transaction_returning_status do
40
- records = should_unarchive_parent_first?(opts) ? unarchival.reverse : unarchival
41
- records.each { |rec| rec.call(opts) }
56
+ private
42
57
 
43
- self
44
- end
45
- end
58
+ def unarchival
59
+ [
60
+ lambda do |validate|
61
+ unarchive_destroyed_dependent_records(validate)
62
+ end,
63
+ lambda do |validate|
64
+ run_callbacks(:unarchive) do
65
+ set_archived_at(nil, validate)
46
66
 
47
- alias_method(:unarchive!, :unarchive)
67
+ each_counter_cache do |assoc_class, counter_cache_column, assoc_id|
68
+ assoc_class.increment_counter(counter_cache_column, assoc_id)
69
+ end
48
70
 
49
- def unarchived?
50
- !archived?
71
+ true
72
+ end
73
+ end
74
+ ]
51
75
  end
52
76
 
53
- def unarchivable?
54
- !archivable?
77
+ def get_archived_record
78
+ self.class.unscoped.find(id)
55
79
  end
56
80
 
57
- private
81
+ def set_archived_at(value, force = nil)
82
+ return self unless archivable?
83
+ record = get_archived_record
84
+ record.archived_at = value
58
85
 
59
- def attempt_notifying_observers(callback)
60
- notify_observers(callback) if respond_to?(:notify_observers)
86
+ begin
87
+ should_ignore_validations?(force) ? record.save(validate: false) : record.save!
88
+ @attributes = record.instance_variable_get('@attributes')
89
+ rescue => error
90
+ record.destroy
91
+ raise error
92
+ end
93
+ end
94
+
95
+ def each_counter_cache
96
+ _reflections.each do |name, reflection|
97
+ next unless respond_to?(name.to_sym)
98
+
99
+ association = send(name.to_sym)
100
+
101
+ next if association.nil?
102
+ next unless reflection.belongs_to? && reflection.counter_cache_column
103
+
104
+ yield(association.class, reflection.counter_cache_column, send(reflection.foreign_key))
105
+ end
61
106
  end
62
107
 
63
108
  def destroy_with_active_archive(force = nil)
@@ -66,53 +111,74 @@ module ActiveArchive
66
111
  save
67
112
  else
68
113
  set_archived_at(Time.now, force)
114
+
69
115
  each_counter_cache do |assoc_class, counter_cache_column, assoc_id|
70
116
  assoc_class.decrement_counter(counter_cache_column, assoc_id)
71
117
  end
72
118
  end
73
- return(true)
119
+
120
+ true
74
121
  end
75
122
 
76
123
  archived? ? self : false
77
124
  end
78
125
 
79
- def each_counter_cache
80
- _reflections.each do |name, reflection|
81
- next unless respond_to?(name.to_sym)
82
-
83
- association = send(name.to_sym)
84
-
85
- next if association.nil?
86
- next unless reflection.belongs_to? && reflection.counter_cache_column
126
+ def add_record_window(_request, name, reflection)
127
+ qtn = reflection.table_name
128
+ window = ActiveArchive.configuration.dependent_record_window
129
+ query = "#{qtn}.archived_at > ? AND #{qtn}.archived_at < ?"
87
130
 
88
- associated_class = association.class
131
+ send(name).unscope(where: :archived_at)
132
+ .where(query, archived_at - window, archived_at + window)
133
+ end
89
134
 
90
- yield(associated_class, reflection.counter_cache_column, send(reflection.foreign_key))
135
+ def unarchive_destroyed_dependent_records(force = nil)
136
+ destroyed_dependent_relations.each do |relation|
137
+ relation.to_a.each do |destroyed_dependent_record|
138
+ destroyed_dependent_record.try(:unarchive, force)
139
+ end
91
140
  end
92
- end
93
141
 
94
- def retrieve_archived_record
95
- self.class.unscoped.find(id)
142
+ reload
96
143
  end
97
144
 
98
145
  # rubocop:disable Metrics/AbcSize
99
- def retrieve_dependent_records
100
- dependent_records = {}
101
-
102
- self.class.reflections.each do |key, ref|
103
- next unless ref.options[:dependent] == :destroy
146
+ def destroyed_dependent_relations
147
+ dependent_permanent_reflections(self.class).map do |name, relation|
148
+ case relation.macro.to_s.gsub('has_', '').to_sym
149
+ when :many
150
+ if archived_at
151
+ add_record_window(send(name), name, relation)
152
+ else
153
+ send(name).unscope(where: :archived_at)
154
+ end
155
+ when :one, :belongs_to
156
+ self.class.unscoped { Array(send(name)) }
157
+ end
158
+ end
159
+ end
160
+ # rubocop:enable Metrics/AbcSize
104
161
 
105
- records = send(key)
106
- next unless records
107
- records.respond_to?(:empty?) ? (next if records.empty?) : (records = [] << records)
162
+ def attempt_notifying_observers(callback)
163
+ notify_observers(callback)
164
+ rescue NoMethodError
165
+ # do nothing
166
+ end
108
167
 
109
- dependent_record = records.first
110
- dependent_record.nil? ? next : dependent_records[dependent_record.class] = records.map(&:id)
168
+ def dependent_record_ids
169
+ dependent_reflections(self.class).reduce({}) do |records, (key, _)|
170
+ found = Array(send(key)).compact
171
+ next records if found.empty?
172
+ records.update(found.first.class => found.map(&:id))
111
173
  end
174
+ end
112
175
 
113
- dependent_records
176
+ def permanently_delete_records_after(&block)
177
+ dependent_records = dependent_record_ids
178
+ result = yield(block)
179
+ permanently_delete_records(dependent_records) if result
180
+ result
114
181
  end
115
- # rubocop:enable Metrics/AbcSize
116
182
 
117
183
  def permanently_delete_records(dependent_records)
118
184
  dependent_records.each do |klass, ids|
@@ -125,89 +191,18 @@ module ActiveArchive
125
191
  end
126
192
  end
127
193
 
128
- def permanently_delete_records_after(&block)
129
- dependent_records = retrieve_dependent_records
130
- dependent_results = yield(block)
131
- permanently_delete_records(dependent_records) if dependent_results
132
- dependent_results
133
- end
134
-
135
- def unarchival
136
- [
137
- ->(validate) { unarchive_destroyed_dependent_records(validate) },
138
- lambda do |validate|
139
- run_callbacks(:unarchive) do
140
- set_archived_at(nil, validate)
141
- each_counter_cache do |assoc_class, counter_cache_column, assoc_id|
142
- assoc_class.increment_counter(counter_cache_column, assoc_id)
143
- end
144
- return(true)
145
- end
146
- end
147
- ]
148
- end
149
-
150
- # rubocop:disable Metrics/LineLength
151
- def dependent_records_for_unarchival(name, reflection)
152
- record = send(name)
153
-
154
- case reflection.macro.to_s.gsub('has_', '').to_sym
155
- when :many
156
- records = archived_at ? set_record_window(record, name, reflection) : record.unscope(where: :archived_at)
157
- when :one, :belongs_to
158
- self.class.unscoped { records = [] << record }
194
+ def dependent_reflections(klass)
195
+ klass.reflections.select do |_, reflection|
196
+ reflection.options[:dependent] == :destroy
159
197
  end
160
-
161
- [records].flatten.compact
162
198
  end
163
- # rubocop:enable Metrics/LineLength
164
199
 
165
- def unarchive_destroyed_dependent_records(force = nil)
166
- self.class.reflections
167
- .select { |_, ref| ref.options[:dependent].to_s == 'destroy' && ref.klass.archivable? }
168
- .each do |name, ref|
169
- dependent_records_for_unarchival(name, ref).each { |rec| rec.try(:unarchive, force) }
170
- reload
171
- end
172
- end
173
-
174
- def set_archived_at(value, force = nil)
175
- return self unless archivable?
176
- record = retrieve_archived_record
177
- record.archived_at = value
178
-
179
- begin
180
- should_ignore_validations?(force) ? record.save(validate: false) : record.save!
181
-
182
- if ::ActiveRecord::VERSION::MAJOR >= 5 && ::ActiveRecord::VERSION::MINOR >= 2
183
- @mutations_before_last_save = record.send(:mutations_from_database)
184
- @attributes_changed_by_setter = HashWithIndifferentAccess.new
185
- elsif ::ActiveRecord::VERSION::MAJOR >= 5
186
- @previous_mutation_tracker = record.send(:previous_mutation_tracker)
187
- elsif ::ActiveRecord::VERSION::MAJOR >= 4
188
- @previously_changed = record.instance_variable_get('@previously_changed')
189
- end
190
-
191
- @changed_attributes = HashWithIndifferentAccess.new
192
- @attributes = record.instance_variable_get('@attributes')
193
- @mutation_tracker = nil
194
- @mutations_from_database = nil
195
- rescue => error
196
- record.destroy
197
- raise(error)
200
+ def dependent_permanent_reflections(klass)
201
+ dependent_reflections(klass).select do |_name, reflection|
202
+ reflection.klass.archivable?
198
203
  end
199
204
  end
200
205
 
201
- def set_record_window(_, name, reflection)
202
- qtn = reflection.table_name
203
- window = ActiveArchive.configuration.dependent_record_window
204
-
205
- query = "#{qtn}.archived_at > ? AND #{qtn}.archived_at < ?"
206
-
207
- send(name).unscope(where: :archived_at)
208
- .where([query, archived_at - window, archived_at + window])
209
- end
210
-
211
206
  def should_force_destroy?(force)
212
207
  force.is_a?(Hash) ? force[:force] : (force == :force)
213
208
  end
@@ -8,12 +8,20 @@ module ActiveArchive
8
8
  end
9
9
 
10
10
  def archive_all(conditions = nil)
11
- conditions ? where(conditions).destroy_all : destroy_all
11
+ (conditions ? where(conditions) : all).to_a.each(&:archive)
12
12
  end
13
13
 
14
+ def archive_all!(conditions = nil)
15
+ (conditions ? where(conditions) : all).to_a.each { |r| r.send(:archive, :force) }
16
+ end
17
+
18
+ alias_method :destroy_all!, :archive_all!
19
+
14
20
  def unarchive_all(conditions = nil)
15
21
  (conditions ? where(conditions) : all).to_a.each(&:unarchive)
16
22
  end
17
23
 
24
+ alias_method :undestroy_all, :unarchive_all
25
+
18
26
  end
19
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveArchive
4
- VERSION ||= '5.1.7'
4
+ VERSION ||= '5.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_archive
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.7
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-04 00:00:00.000000000 Z
11
+ date: 2018-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: database_cleaner
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
56
+ name: fasterer
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: sqlite3
70
+ name: generator_spec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: database_cleaner
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: generator_spec
98
+ name: reek
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: fasterer
112
+ name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: reek
126
+ name: rubocop
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: rubocop
140
+ name: sqlite3
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -160,7 +160,7 @@ files:
160
160
  - ".DS_Store"
161
161
  - ".fasterer.yml"
162
162
  - ".gitignore"
163
- - ".reek"
163
+ - ".reek.yml"
164
164
  - ".rspec"
165
165
  - ".rubocop.yml"
166
166
  - ".travis.yml"
data/.reek DELETED
@@ -1,22 +0,0 @@
1
- ---
2
- Attribute:
3
- enabled: false
4
- DuplicateMethodCall:
5
- enabled: false
6
- FeatureEnvy:
7
- enabled: false
8
- IrresponsibleModule:
9
- enabled: false
10
- ManualDispatch:
11
- enabled: false
12
- NestedIterators:
13
- max_allowed_nesting: 2
14
- NilCheck:
15
- enabled: false
16
- TooManyStatements:
17
- max_statements: 10
18
- exclude:
19
- - 'ActiveArchive::Base#retrieve_dependent_records'
20
- - 'ActiveArchive::Base#set_archived_at'
21
- UtilityFunction:
22
- enabled: false