From 1173a451c45dc7c5db1ed1905992b7e35c6c3ea3 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Wed, 16 Oct 2024 13:33:53 +0000 Subject: [PATCH] Refs #37825 - Fix resource nesting for PreloadScopesBuilder Without this patch Ansible-related scopes for Host::Managed.includes() would look like: [ { host_ansible_roles: :ansible_roles }, { ansible_role: [{ ansible_variables: [:lookup_values] }] } ], which for some reason worked before Rails 7. After this patch, it looks like: [ { host_ansible_roles: { ansible_role: [{ ansible_variables: [:lookup_values] }] } } ]. --- app/services/foreman/preload_scopes_builder.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/services/foreman/preload_scopes_builder.rb b/app/services/foreman/preload_scopes_builder.rb index 2fed836d0d3..0d8a1e3b9f5 100644 --- a/app/services/foreman/preload_scopes_builder.rb +++ b/app/services/foreman/preload_scopes_builder.rb @@ -26,7 +26,7 @@ def preload_scopes end def build_scopes(model, ignore: [], assoc_name: nil) - scopes = dependent_associations(model).map do |assoc| + scopes = dependent_associations(model, ignore: ignore).map do |assoc| next if ignore.include?(assoc.name) dep_associations = dependent_associations(assoc.klass) @@ -34,8 +34,14 @@ def build_scopes(model, ignore: [], assoc_name: nil) ignore += dep_associations.select { |to_ignore| to_ignore.options.key?(:through) }.map(&:name) ignore << assoc.name dep_scopes = build_scopes(assoc.klass, ignore: ignore, assoc_name: assoc.name) - if assoc.options.key?(:through) && dep_scopes.is_a?(Hash) - next { assoc.options[:through] => assoc.source_reflection_name }.merge(dep_scopes) + if assoc.options.key?(:through) + deps = dependent_associations(assoc.source_reflection.klass, ignore: ignore) + if deps.any? + dep_scopes = build_scopes(assoc.source_reflection.klass, ignore: ignore, assoc_name: assoc.source_reflection_name) + next { assoc.options[:through] => dep_scopes } + else + next { assoc.options[:through] => assoc.source_reflection_name } + end end next dep_scopes end @@ -46,9 +52,9 @@ def build_scopes(model, ignore: [], assoc_name: nil) scopes.empty? ? assoc_name : { assoc_name => scopes } end - def dependent_associations(model) + def dependent_associations(model, ignore: []) model.reflect_on_all_associations.select do |assoc| - (assoc.options.values & [:destroy, :delete_all, :destroy_async]).any? + !ignore.include?(assoc.name) && (assoc.options.values & [:destroy, :delete_all, :destroy_async]).any? end end end