Skip to content

Commit

Permalink
Fix an issue in the where.associated method
Browse files Browse the repository at this point in the history
  • Loading branch information
saleh-alhaddad committed Feb 17, 2024
1 parent 9b343c2 commit 77360db
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 1 deletion.
12 changes: 12 additions & 0 deletions activerecord/CHANGELOG.md
Expand Up @@ -3,6 +3,18 @@

*Jason Nochlin*

* Fix an issue in the `where.associated` method only allows filtering associated records with an `inner join`,
which can potentially override existing join types in the query.
The fix ensures that the association is joined using the appropriate join type (either inner join or left outer join) based on the existing joins in the scope.
This prevents unintentional overrides of existing join types and ensures consistency in the generated SQL queries.
Example:
asoiciated will use left_joins alternative use deafult joins
```ruby
Post.left_joins(:author).where.associated(: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.
Expand Down
9 changes: 8 additions & 1 deletion activerecord/lib/active_record/relation/query_methods.rb
Expand Up @@ -72,10 +72,17 @@ 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
#
# Additionally, you can define joine type in the scope and associated will not use default that is joins
# Example: Post.left_joins(:author).where.associated(:author)
#
def associated(*associations)
associations.each do |association|
reflection = scope_association_reflection(association)
@scope.joins!(association)
unless @scope.joins_values.include?(reflection.name) || @scope.left_outer_joins_values.include?(reflection.name)
@scope.joins!(association)
end

if reflection.options[:class_name]
self.not(association => { reflection.association_primary_key => nil })
else
Expand Down
21 changes: 21 additions & 0 deletions activerecord/test/cases/relation/where_chain_test.rb
Expand Up @@ -92,6 +92,27 @@ 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_add_joins_before
Comment.joins(:children).where.associated(:children).tap do |relation|
assert_includes relation, comments(:greetings)
assert_not_includes relation, comments(:more_greetings)
end
end

def test_associated_with_add_left_joins_before
Comment.left_joins(:children).where.associated(:children).tap do |relation|
assert_includes relation, comments(:greetings)
assert_not_includes relation, comments(:more_greetings)
end
end

def test_associated_with_add_left_outer_joins_before
Comment.left_outer_joins(:children).where.associated(:children).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
Expand Down

0 comments on commit 77360db

Please sign in to comment.