Fix disable_joins when using an enum STI type

When a model has an STI enum type, the type wasn't properly applied when
disable joins was set to true. In this case we need to apply the scope
from the association in `add_constraints` so that `type` is included in
the query. Otherwise in a `has_one :through` with `type` all records
will be returned because we're not filtering on type.

Long term I think this might be in the wrong place and that we want to
do this in a new definition of `target_scope` but that's a future
refactoring that needs to be done.
This commit is contained in:
eileencodes 2021-06-24 10:08:43 -04:00
parent 25f2341968
commit 207747ec2d
No known key found for this signature in database
GPG Key ID: BA5C575120BBE8DF
3 changed files with 29 additions and 1 deletions

View File

@ -32,6 +32,12 @@ module ActiveRecord
def add_constraints(reflection, key, join_ids, owner, ordered)
scope = reflection.build_scope(reflection.aliased_table).where(key => join_ids)
relation = reflection.klass.scope_for_association
scope.merge!(
relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins)
)
scope = reflection.constraints.inject(scope) do |memo, scope_chain_item|
item = eval_scope(reflection, scope_chain_item, owner)
scope.unscope!(*item.unscope_values)

View File

@ -8,9 +8,11 @@ require "models/project"
require "models/developer"
require "models/company"
require "models/computer"
require "models/club"
require "models/membership"
class HasOneThroughDisableJoinsAssociationsTest < ActiveRecord::TestCase
fixtures :members, :organizations, :projects, :developers, :companies
fixtures :members, :organizations, :projects, :developers, :companies, :clubs, :memberships
def setup
@member = members(:groucho)
@ -61,4 +63,23 @@ class HasOneThroughDisableJoinsAssociationsTest < ActiveRecord::TestCase
assert_no_match(/INNER JOIN/, nj)
end
end
def test_disable_joins_through_with_enum_type
joins = capture_sql { @member.club }
no_joins = capture_sql { @member.club_without_joins }
assert_equal 1, joins.size
assert_equal 2, no_joins.size
assert_match(/INNER JOIN/, joins.first)
no_joins.each do |nj|
assert_no_match(/INNER JOIN/, nj)
end
if current_adapter?(:Mysql2Adapter)
assert_match(/`memberships`.`type`/, no_joins.first)
else
assert_match(/"memberships"."type"/, no_joins.first)
end
end
end

View File

@ -5,6 +5,7 @@ class Member < ActiveRecord::Base
has_one :selected_membership
has_one :membership
has_one :club, through: :current_membership
has_one :club_without_joins, through: :current_membership, source: :club, disable_joins: true
has_one :selected_club, through: :selected_membership, source: :club
has_one :favorite_club, -> { where "memberships.favorite = ?", true }, through: :membership, source: :club
has_one :hairy_club, -> { where clubs: { name: "Moustache and Eyebrow Fancier Club" } }, through: :membership, source: :club