summaryrefslogtreecommitdiff
path: root/app/models/concerns/batch_nullify_dependent_associations.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/concerns/batch_nullify_dependent_associations.rb')
-rw-r--r--app/models/concerns/batch_nullify_dependent_associations.rb27
1 files changed, 27 insertions, 0 deletions
diff --git a/app/models/concerns/batch_nullify_dependent_associations.rb b/app/models/concerns/batch_nullify_dependent_associations.rb
new file mode 100644
index 00000000000..c95b5b64a43
--- /dev/null
+++ b/app/models/concerns/batch_nullify_dependent_associations.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+# Provides a way to execute nullify behaviour in batches
+# to avoid query timeouts for really big tables
+# Assumes that associations have `dependent: :nullify` statement
+module BatchNullifyDependentAssociations
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def dependent_associations_to_nullify
+ reflect_on_all_associations(:has_many).select { |assoc| assoc.options[:dependent] == :nullify }
+ end
+ end
+
+ def nullify_dependent_associations_in_batches(exclude: [], batch_size: 100)
+ self.class.dependent_associations_to_nullify.each do |association|
+ next if association.name.in?(exclude)
+
+ loop do
+ # rubocop:disable GitlabSecurity/PublicSend
+ update_count = public_send(association.name).limit(batch_size).update_all(association.foreign_key => nil)
+ # rubocop:enable GitlabSecurity/PublicSend
+ break if update_count < batch_size
+ end
+ end
+ end
+end