mirror of https://github.com/rails/rails
Merge pull request #41012 from kamipo/fix_complicated_through_association
Fix complicated has_many through with nested where condition
This commit is contained in:
commit
21b8d9b08c
|
@ -131,11 +131,14 @@ module ActiveRecord
|
|||
if scope_chain_item == chain_head.scope
|
||||
scope.merge! item.except(:where, :includes, :unscope, :order)
|
||||
elsif !item.references_values.empty?
|
||||
join_dependency = item.construct_join_dependency(
|
||||
item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
|
||||
)
|
||||
scope.joins!(*item.joins_values, join_dependency)
|
||||
scope.left_outer_joins!(*item.left_outer_joins_values)
|
||||
scope.joins_values |= item.joins_values
|
||||
scope.left_outer_joins_values |= item.left_outer_joins_values
|
||||
|
||||
associations = item.eager_load_values | item.includes_values
|
||||
|
||||
unless associations.empty?
|
||||
scope.joins_values << item.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
||||
end
|
||||
end
|
||||
|
||||
reflection.all_includes do
|
||||
|
|
|
@ -1140,7 +1140,7 @@ module ActiveRecord
|
|||
self.references_values |= references unless references.empty?
|
||||
|
||||
parts = predicate_builder.build_from_hash(opts) do |table_name|
|
||||
lookup_reflection_from_join_dependencies(table_name)
|
||||
lookup_table_klass_from_join_dependencies(table_name)
|
||||
end
|
||||
when Arel::Nodes::Node
|
||||
parts = [opts]
|
||||
|
@ -1153,9 +1153,9 @@ module ActiveRecord
|
|||
alias :build_having_clause :build_where_clause
|
||||
|
||||
private
|
||||
def lookup_reflection_from_join_dependencies(table_name)
|
||||
def lookup_table_klass_from_join_dependencies(table_name)
|
||||
each_join_dependencies do |join|
|
||||
return join.reflection if table_name == join.table_name
|
||||
return join.base_klass if table_name == join.table_name
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
@ -1366,7 +1366,7 @@ module ActiveRecord
|
|||
elsif field.match?(/\A\w+\.\w+\z/)
|
||||
table, column = field.split(".")
|
||||
predicate_builder.resolve_arel_attribute(table, column) do
|
||||
lookup_reflection_from_join_dependencies(table)
|
||||
lookup_table_klass_from_join_dependencies(table)
|
||||
end
|
||||
else
|
||||
yield field
|
||||
|
|
|
@ -33,10 +33,13 @@ module ActiveRecord
|
|||
return self
|
||||
end
|
||||
|
||||
reflection ||= yield table_name if block_given?
|
||||
if reflection
|
||||
association_klass = reflection.klass unless reflection.polymorphic?
|
||||
elsif block_given?
|
||||
association_klass = yield table_name
|
||||
end
|
||||
|
||||
if reflection && !reflection.polymorphic?
|
||||
association_klass = reflection.klass
|
||||
if association_klass
|
||||
arel_table = association_klass.arel_table
|
||||
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
||||
TableMetadata.new(association_klass, arel_table, reflection)
|
||||
|
|
|
@ -66,6 +66,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|||
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.left_joins(:comments))
|
||||
end
|
||||
|
||||
def test_through_association_with_through_scope_and_nested_where
|
||||
company = Company.create!(name: "special")
|
||||
developer = SpecialDeveloper.create!
|
||||
SpecialContract.create!(company: company, special_developer: developer)
|
||||
|
||||
assert_equal [developer], company.special_developers.where.not("contracts.id": nil)
|
||||
end
|
||||
|
||||
def test_preload_with_nested_association
|
||||
posts = Post.where(id: [authors(:david).id, authors(:mary).id]).
|
||||
preload(:author, :author_favorites_with_scope).order(:id).to_a
|
||||
|
|
|
@ -13,6 +13,8 @@ class Company < AbstractCompany
|
|||
has_one :dummy_account, foreign_key: "firm_id", class_name: "Account"
|
||||
has_many :contracts
|
||||
has_many :developers, through: :contracts
|
||||
has_many :special_contracts, -> { includes(:special_developer).where.not("developers.id": nil) }
|
||||
has_many :special_developers, through: :special_contracts
|
||||
|
||||
alias_attribute :new_name, :name
|
||||
attribute :metadata, :json
|
||||
|
|
|
@ -30,3 +30,9 @@ end
|
|||
class NewContract < Contract
|
||||
validates :company_id, presence: true
|
||||
end
|
||||
|
||||
class SpecialContract < ActiveRecord::Base
|
||||
self.table_name = "contracts"
|
||||
belongs_to :company
|
||||
belongs_to :special_developer, foreign_key: "developer_id"
|
||||
end
|
||||
|
|
|
@ -114,6 +114,11 @@ end
|
|||
class SubDeveloper < Developer
|
||||
end
|
||||
|
||||
class SpecialDeveloper < ActiveRecord::Base
|
||||
self.table_name = "developers"
|
||||
has_many :special_contracts, foreign_key: "developer_id"
|
||||
end
|
||||
|
||||
class SymbolIgnoredDeveloper < ActiveRecord::Base
|
||||
self.table_name = "developers"
|
||||
self.ignored_columns = [:first_name, :last_name]
|
||||
|
|
Loading…
Reference in New Issue