rails_delete_all_and_assocs_without_instantiation 0.0.2 → 0.0.4
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9acdcdfc546fa1f49d03d2f52f785e8a012211cb2fead2ff5dad11767d125cc
|
4
|
+
data.tar.gz: e46db80ef699f7ad8a8ffbd4f9689f15c019826ad65acdbbd1d982cdaa423a52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87cdde62744d43c2567d6b55a59ccddcd0a412925c6d396294396839d12036dab633d3a3fd09d3284952bd5a351d4467c27d0426e5cf088b92b83963860f284c
|
7
|
+
data.tar.gz: 19ac4b45404cd36e02d1f1aac7cf8a9598a862ae272e32553258a377dbf2af8aa28ffc7047aa6e817898ab32fbb8922180b4b48bd5009d4243365fbb30187354
|
data/README.md
CHANGED
@@ -36,3 +36,22 @@ class User < ApplicationRecord
|
|
36
36
|
has_many :creator_accounts, -> (user_id) { where(creator_id: user_id) }, dependent: :destroy
|
37
37
|
end
|
38
38
|
```
|
39
|
+
|
40
|
+
# Customization
|
41
|
+
```
|
42
|
+
class User
|
43
|
+
# This is a way you can do more advanced filtering on association dependencies, and not just wipe everything
|
44
|
+
def self.delete_all_and_assocs_without_instantiation_builder models_and_ids_list = {}, errors = [], options = {}
|
45
|
+
original_account_ids = models_and_ids_list['Account']
|
46
|
+
models_and_ids_list, errors = super(models_and_ids_list, errors, options)
|
47
|
+
# we've ignored the deletion command that may or may not have been created by your assoc definition
|
48
|
+
models_and_ids_list['Account'] = original_account_ids
|
49
|
+
|
50
|
+
query = self.where({}).includes(:accounts).joins(:accounts).where(accounts: {marketable: true})
|
51
|
+
account_ids = query.collect{|pro| pro.accounts.map(&:id) }.flatten
|
52
|
+
models_and_ids_list, errors = Account.unscoped.where(id: account_ids).delete_all_and_assocs_without_instantiation_builder(models_and_ids_list, errors, options)
|
53
|
+
|
54
|
+
return models_and_ids_list, errors
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
data/lib/rails_delete_all_and_assocs_without_instantiation/delete_all_and_assocs_extension.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
module RailsDeleteAllAndAssocsWithoutInstantiation
|
2
2
|
module DeleteAllAndAssocsWithoutInstantiation
|
3
|
+
MATCH_DEPENDENT_ASSOC_VALUE = [
|
4
|
+
:destroy,
|
5
|
+
'destroy',
|
6
|
+
:delete_all,
|
7
|
+
'delete_all',
|
8
|
+
:destroy_async,
|
9
|
+
'destroy_async',
|
10
|
+
]
|
3
11
|
|
4
12
|
# rails interpretation is different than expected:
|
5
13
|
# https://makandracards.com/makandra/32175-don-t-forget-automatically-remove-join-records-on-has_many-through-associations
|
@@ -22,25 +30,25 @@ module RailsDeleteAllAndAssocsWithoutInstantiation
|
|
22
30
|
# force_through_destroy_chains = options[:force_destroy_chain] || {}
|
23
31
|
# do_not_destroy_self = options[:do_not_destroy] || {}
|
24
32
|
|
25
|
-
current_class = self
|
33
|
+
current_class = self.name
|
26
34
|
current_query = self
|
27
35
|
ids = current_query.pluck(:id)
|
28
36
|
models_and_ids_list[name] ||= []
|
29
37
|
|
30
38
|
# prevent infinite recursion here.
|
31
39
|
ids = ids - models_and_ids_list[self.name]
|
32
|
-
if ids.none?
|
40
|
+
if ids.none? || ids.nil?
|
33
41
|
return models_and_ids_list, errors
|
34
42
|
end
|
35
43
|
|
36
|
-
models_and_ids_list[self.name]
|
44
|
+
models_and_ids_list[self.name] += ids
|
37
45
|
|
38
46
|
# if do_not_destroy_self != true
|
39
47
|
# models_and_ids_list[name] += ids
|
40
48
|
# end
|
41
49
|
|
42
50
|
# ignore associations that aren't dependent destroyable.
|
43
|
-
destroy_association_names = self.reflect_on_all_associations.reject{|v| !
|
51
|
+
destroy_association_names = self.reflect_on_all_associations.reject{|v| !MATCH_DEPENDENT_ASSOC_VALUE.include?(v.options&.dig(:dependent)) }.collect{ |v| v.name }
|
44
52
|
|
45
53
|
|
46
54
|
# associations that we might not necessarilly need to delete, but need to go through
|
@@ -145,24 +153,38 @@ module RailsDeleteAllAndAssocsWithoutInstantiation
|
|
145
153
|
retry_due_to_errors = []
|
146
154
|
retry_to_capture_errors = []
|
147
155
|
|
156
|
+
if options[:verbose]
|
157
|
+
puts "DELETION STRUCTURE"
|
158
|
+
puts built_deletions.inspect
|
159
|
+
end
|
160
|
+
|
148
161
|
ActiveRecord::Base.transaction do
|
149
162
|
built_deletions.keys.reverse.each do |class_name|
|
163
|
+
ids = "N/A"
|
150
164
|
begin
|
151
165
|
ids = built_deletions[class_name]
|
152
|
-
next if ids.none?
|
166
|
+
next if ids.none? || ids.nil?
|
153
167
|
klass = class_name.constantize
|
154
168
|
klass.unscoped.where(id: ids).delete_all
|
155
169
|
rescue Exception => e
|
170
|
+
puts "DEL ATTEMPT 1: #{class_name}.unscoped.where(id: #{ids}).delete_all" if options[:verbose]
|
156
171
|
retry_due_to_errors << class_name
|
157
172
|
end
|
158
173
|
end
|
159
174
|
|
175
|
+
if options[:verbose]
|
176
|
+
puts "RETRY DUE TO ERRORS:"
|
177
|
+
puts retry_due_to_errors.inspect
|
178
|
+
end
|
179
|
+
|
160
180
|
# ActiveRecord::InvalidForeignKey can cause issues in ordering.
|
161
|
-
retry_due_to_errors.
|
181
|
+
retry_due_to_errors.each do |class_name|
|
182
|
+
ids = "N/A"
|
162
183
|
begin
|
163
184
|
ids = built_deletions[class_name]
|
164
|
-
next if ids.none?
|
185
|
+
next if ids.none? || ids.nil?
|
165
186
|
klass = class_name.constantize
|
187
|
+
puts "DEL ATTEMPT 2: #{class_name}.unscoped.where(id: #{ids}).delete_all" if options[:verbose]
|
166
188
|
klass.unscoped.where(id: ids).delete_all
|
167
189
|
# if Rails.env.test? || Rails.env.development?
|
168
190
|
# if count = klass.unscoped.where(id: ids).count > 0
|
@@ -172,20 +194,27 @@ module RailsDeleteAllAndAssocsWithoutInstantiation
|
|
172
194
|
rescue Exception => e
|
173
195
|
# ActiveRecord::Base.transaction obscures the actual errors
|
174
196
|
# - need to run again outside of block to get actual error
|
175
|
-
retry_to_capture_errors << [
|
197
|
+
retry_to_capture_errors << [class_name, ids]
|
176
198
|
raise ActiveRecord::Rollback
|
177
199
|
end
|
178
200
|
end
|
179
201
|
end
|
180
202
|
|
181
|
-
retry_to_capture_errors.each do |
|
203
|
+
retry_to_capture_errors.each do |class_name, ids|
|
204
|
+
if ids == "N/A"
|
205
|
+
errors << ["Internal Server Error, could not locate IDs", class_name]
|
206
|
+
next
|
207
|
+
end
|
182
208
|
begin
|
209
|
+
klass = class_name.constantize
|
210
|
+
puts "DEL ATTEMPT 3: #{class_name}.unscoped.where(id: #{ids}).delete_all" if options[:verbose]
|
183
211
|
klass.unscoped.where(id: ids).delete_all
|
184
212
|
# should never get past this line, we're expecting an error!
|
185
213
|
# - if we do, maybe was an intermittent issue. Call ourselves recursively to try again.
|
186
|
-
return current_query.delete_all_and_assocs_without_instantiation(options)
|
214
|
+
# return current_query.delete_all_and_assocs_without_instantiation(options)
|
215
|
+
errors << ["#{class_name} - expected error, ran into 2 errors on previous deletion attempts", ids]
|
187
216
|
rescue Exception => e
|
188
|
-
errors << e.class.to_s + "; " + e.message
|
217
|
+
errors << [e.class.to_s + "; " + e.message, e.backtrace]
|
189
218
|
end
|
190
219
|
|
191
220
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rails_delete_all_and_assocs_without_instantiation}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.4"
|
6
6
|
s.date = %q{2023-03-02}
|
7
7
|
s.authors = ["benjamin.dana.software.dev@gmail.com"]
|
8
8
|
s.summary = %q{Non-instantiated way of deleting records with dependencies quickly without instantiation.}
|