diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2017-09-07 07:33:38 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2017-09-07 07:43:44 +0900 |
commit | 3acc5d6ef7b3f000d0c541b9dc2881a8b7f40f75 (patch) | |
tree | 24d85800fdf8b5da44d07fa4fd2a55306914d4c9 /activerecord/lib/active_record/associations | |
parent | 0a94612a979762e1bbeb9cff13322e3f9f721ca3 (diff) | |
download | rails-3acc5d6ef7b3f000d0c541b9dc2881a8b7f40f75.tar.gz rails-3acc5d6ef7b3f000d0c541b9dc2881a8b7f40f75.tar.bz2 rails-3acc5d6ef7b3f000d0c541b9dc2881a8b7f40f75.zip |
`has_many :through` with unscope should affect to through scope
The order of scope evaluation should be from through scope to the
association's own scope. Otherwise the association's scope cannot affect
to through scope.
Fixes #13677.
Closes #28449.
Diffstat (limited to 'activerecord/lib/active_record/associations')
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 35 |
1 files changed, 14 insertions, 21 deletions
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 0e849c06ef..4220a1499a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -24,10 +24,10 @@ module ActiveRecord scope = klass.unscoped owner = association.owner alias_tracker = AliasTracker.create(klass.connection, klass.table_name) - chain_head, chain_tail = get_chain(reflection, association, alias_tracker) + chain = get_chain(reflection, association, alias_tracker) scope.extending! reflection.extensions - add_constraints(scope, owner, chain_head, chain_tail) + add_constraints(scope, owner, chain) end def join_type @@ -98,7 +98,6 @@ module ActiveRecord end class ReflectionProxy < SimpleDelegator # :nodoc: - attr_accessor :next attr_reader :alias_name def initialize(reflection, alias_name) @@ -111,36 +110,32 @@ module ActiveRecord def get_chain(reflection, association, tracker) name = reflection.name - runtime_reflection = Reflection::RuntimeReflection.new(reflection, association) - previous_reflection = runtime_reflection + chain = [Reflection::RuntimeReflection.new(reflection, association)] reflection.chain.drop(1).each do |refl| alias_name = tracker.aliased_table_for( refl.table_name, refl.alias_candidate(name), refl.klass.type_caster ) - proxy = ReflectionProxy.new(refl, alias_name) - previous_reflection.next = proxy - previous_reflection = proxy + chain << ReflectionProxy.new(refl, alias_name) end - [runtime_reflection, previous_reflection] + chain end - def add_constraints(scope, owner, chain_head, chain_tail) - owner_reflection = chain_tail + def add_constraints(scope, owner, chain) + owner_reflection = chain.last table = owner_reflection.alias_name scope = last_chain_scope(scope, table, owner_reflection, owner) - reflection = chain_head - while reflection + chain.each_cons(2) do |reflection, next_reflection| table = reflection.alias_name - next_reflection = reflection.next - - unless reflection == chain_tail - foreign_table = next_reflection.alias_name - scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection) - end + foreign_table = next_reflection.alias_name + scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection) + end + chain_head = chain.first + chain.reverse_each do |reflection| + table = reflection.alias_name # Exclude the scope of the association itself, because that # was already merged in the #scope method. reflection.constraints.each do |scope_chain_item| @@ -158,8 +153,6 @@ module ActiveRecord scope.where_clause += item.where_clause scope.order_values |= item.order_values end - - reflection = next_reflection end scope |