From 7b3278258ffb1a312882f4b1d199040a0a980044 Mon Sep 17 00:00:00 2001 From: saleh-alhaddad Date: Wed, 14 Feb 2024 09:13:59 +0300 Subject: [PATCH] Add support join types in where.associated method --- activerecord/CHANGELOG.md | 10 ++++++++++ .../lib/active_record/relation/query_methods.rb | 13 +++++++++++-- .../test/cases/relation/where_chain_test.rb | 7 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 9f8beb5aad5c..340919fde04b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -3,6 +3,16 @@ *Jason Nochlin* +* Adds support to change join type in the `where.associated` method. + By default associated method use joins association, Support join type are joins, left_joins and left_outer_joins. + + In this example change default join type to the `left_joins` + ```ruby + Post.where.associated(join_type: :left_joins, :author) + ``` + + *Saleh Alhaddad* + * Fix an issue where `ActiveRecord::Encryption` configurations are not ready before the loading of Active Record models, when an application is eager loaded. As a result, encrypted attributes could be misconfigured in some cases. diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index b9dc7392323c..5784b1960262 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -72,10 +72,19 @@ def not(opts, *rest) # # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id" # # INNER JOIN "comments" ON "comments"."post_id" = "posts"."id" # # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL - def associated(*associations) + # + # Additionally, you can change join type by one of the allowed types, joins, left_joins and left_outer_joins + # Example: Post.where.associated(join_type: :left_joins, :author) + # + def associated(*associations, join_type: :joins) + allowed_types = [:joins, :left_joins, :left_outer_joins] + unless allowed_types.include?(join_type.to_sym) + raise ArgumentError.new("An `#{join_type}` does not exist on the allowed association `#{allowed_types.join(', ')}`.") + end + associations.each do |association| reflection = scope_association_reflection(association) - @scope.joins!(association) + @scope.send("#{join_type}!", association) if reflection.options[:class_name] self.not(association => { reflection.association_primary_key => nil }) else diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb index db0860f37831..addcfc66e04d 100644 --- a/activerecord/test/cases/relation/where_chain_test.rb +++ b/activerecord/test/cases/relation/where_chain_test.rb @@ -92,6 +92,13 @@ def test_associated_with_enum_extended_late assert_equal Author.find(2), Author.order(id: :desc).joins(:reading_listing).where.associated(:reading_listing).extending(Author::NamedExtension).first end + def test_associated_with_change_join_type + Comment.where.associated(:children, join_type: :left_joins).tap do |relation| + assert_includes relation, comments(:greetings) + assert_not_includes relation, comments(:more_greetings) + end + end + def test_missing_with_association assert_predicate posts(:authorless).author, :blank? assert_equal [posts(:authorless)], Post.where.missing(:author).to_a