From 08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb Mon Sep 17 00:00:00 2001 From: eileencodes Date: Sat, 18 Oct 2014 14:53:21 -0400 Subject: Add PolymorphicReflection and constraints method `#constraints` builds a flattened version of `scope_chain` to allow it to be accessible without requiring an index when iterating over the `scope_chain` --- .../associations/association_scope.rb | 7 +-- activerecord/lib/active_record/reflection.rb | 59 +++++++++++++++++++++- 2 files changed, 62 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 53f65920e1..668798c246 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -131,8 +131,6 @@ module ActiveRecord def add_constraints(scope, owner, assoc_klass, refl, tracker) chain = refl.chain - scope_chain = refl.scope_chain - connection = tracker.connection tables = construct_tables(chain, assoc_klass, refl, tracker) @@ -140,6 +138,7 @@ module ActiveRecord table = tables.last scope = last_chain_scope(scope, table, owner_reflection, owner, connection, assoc_klass) + # chain.first always == refl chain.each_with_index do |reflection, i| table, foreign_table = tables.shift, tables.first @@ -151,9 +150,11 @@ module ActiveRecord is_first_chain = i == 0 klass = is_first_chain ? assoc_klass : reflection.klass + items = reflection.constraints + # Exclude the scope of the association itself, because that # was already merged in the #scope method. - scope_chain[i].each do |scope_chain_item| + items.each do |scope_chain_item| item = eval_scope(klass, scope_chain_item, owner) if scope_chain_item == refl.scope diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index dd746a4e10..1bc92b1587 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -161,7 +161,12 @@ module ActiveRecord macro end + + def constraints + scope ? [scope] : [] + end end + # Base class for AggregateReflection and AssociationReflection. Objects of # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods. # @@ -697,13 +702,59 @@ module ActiveRecord def chain @chain ||= begin a = source_reflection.chain - b = through_reflection.chain + b = through_reflection.chain.map(&:dup) + + if options[:source_type] + b[0] = PolymorphicReflection.new(b[0], self) + end + chain = a + b chain[0] = self # Use self so we don't lose the information from :source_type chain end end + class PolymorphicReflection + def initialize(reflection, prev_reflection) + @reflection = reflection + @prev_reflection = prev_reflection + end + + def klass + @reflection.klass + end + + def scope + @reflection.scope + end + + def table_name + @reflection.table_name + end + + def plural_name + @reflection.plural_name + end + + def join_keys(assoc_klass) + @reflection.join_keys(assoc_klass) + end + + def type + @reflection.type + end + + def constraints + [source_type_info] + end + + def source_type_info + type = @prev_reflection.foreign_type + source_type = @prev_reflection.options[:source_type] + lambda { |object| where(type => source_type) } + end + end + # Consider the following example: # # class Person @@ -855,6 +906,12 @@ module ActiveRecord check_validity_of_inverse! end + def constraints + scope_chain = source_reflection.constraints + scope_chain << scope if scope + scope_chain + end + protected def actual_source_reflection # FIXME: this is a horrible name -- cgit v1.2.3 From 69d05ae3e52fa382748982ad06c0d0a1014ebc91 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Fri, 31 Oct 2014 09:10:40 -0400 Subject: Add RuntimeReflection for recursive access to chain The `RuntimeReflection` class allows the reflection to be accessed at runtime - then we always know which reflection we are accessing in the chain. The `#get_chain` method then allows us to recursively access the chain through the `RuntimeReflection`. --- .../associations/association_scope.rb | 57 ++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 668798c246..95c4cf2500 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -34,9 +34,10 @@ module ActiveRecord scope = klass.unscoped owner = association.owner alias_tracker = AliasTracker.empty connection + chain = get_chain(reflection, association) scope.extending! Array(reflection.options[:extend]) - add_constraints(scope, owner, klass, reflection, alias_tracker) + add_constraints(scope, owner, klass, reflection, alias_tracker, chain) end def join_type @@ -129,9 +130,59 @@ module ActiveRecord scope = scope.joins(join(foreign_table, constraint)) end - def add_constraints(scope, owner, assoc_klass, refl, tracker) - chain = refl.chain + class RuntimeReflection + def initialize(reflection, association) + @reflection = reflection + @association = association + end + + def klass + @association.klass + end + + def scope + @reflection.scope + end + + def table_name + if @reflection.polymorphic? + # If this is a polymorphic belongs_to, we want to get the klass from the + # association because it depends on the polymorphic_type attribute of + # the owner + klass.table_name + else + @reflection.table_name + end + end + + def plural_name + @reflection.plural_name + end + + def join_keys(assoc_klass) + @reflection.join_keys(assoc_klass) + end + + def type + @reflection.type + end + + def constraints + @reflection.constraints + end + + def source_type_info + @reflection.source_type_info + end + end + + def get_chain(reflection, association) + chain = reflection.chain.dup + chain[0] = RuntimeReflection.new(reflection, association) + chain + end + def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) tables = construct_tables(chain, assoc_klass, refl, tracker) owner_reflection = chain.last -- cgit v1.2.3 From 076682692cd363765e6e5235c691474a071a01de Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 4 Nov 2014 13:58:15 -0500 Subject: Refactor construct_tables method Move method structure into reflection classes for accessibly on each reflection rather than by traversing the chain. --- .../associations/association_scope.rb | 46 +++++----------------- activerecord/lib/active_record/reflection.rb | 10 +++++ 2 files changed, 20 insertions(+), 36 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 95c4cf2500..4907d1cf6c 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -63,22 +63,12 @@ module ActiveRecord private - def construct_tables(chain, klass, refl, alias_tracker) + def construct_tables(chain, alias_tracker, name) chain.map do |reflection| - alias_tracker.aliased_table_for( - table_name_for(reflection, klass, refl), - table_alias_for(reflection, refl, reflection != refl), - type_caster: klass.type_caster, - ) + reflection.alias_name(name, alias_tracker) end end - def table_alias_for(reflection, refl, join = false) - name = "#{reflection.plural_name}_#{alias_suffix(refl)}" - name << "_join" if join - name - end - def join(table, constraint) table.create_join(table, table.create_on(constraint), join_type) end @@ -145,14 +135,7 @@ module ActiveRecord end def table_name - if @reflection.polymorphic? - # If this is a polymorphic belongs_to, we want to get the klass from the - # association because it depends on the polymorphic_type attribute of - # the owner - klass.table_name - else - @reflection.table_name - end + klass.table_name end def plural_name @@ -174,6 +157,12 @@ module ActiveRecord def source_type_info @reflection.source_type_info end + + def alias_name(name, alias_tracker) + alias_name = "#{plural_name}_#{name}_join" + table_name = klass.table_name + alias_tracker.aliased_table_for(table_name, alias_name) + end end def get_chain(reflection, association) @@ -183,7 +172,7 @@ module ActiveRecord end def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) - tables = construct_tables(chain, assoc_klass, refl, tracker) + tables = construct_tables(chain, tracker, refl.name) owner_reflection = chain.last table = tables.last @@ -225,21 +214,6 @@ module ActiveRecord scope end - def alias_suffix(refl) - refl.name - end - - def table_name_for(reflection, klass, refl) - if reflection == refl - # If this is a polymorphic belongs_to, we want to get the klass from the - # association because it depends on the polymorphic_type attribute of - # the owner - klass.table_name - else - reflection.table_name - end - end - def eval_scope(klass, scope, owner) klass.unscoped.instance_exec(owner, &scope) end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 1bc92b1587..83771bd5dc 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -165,6 +165,11 @@ module ActiveRecord def constraints scope ? [scope] : [] end + + def alias_name(name, alias_tracker) + alias_name = "#{plural_name}_#{name}" + alias_tracker.aliased_table_for(table_name, alias_name) + end end # Base class for AggregateReflection and AssociationReflection. Objects of @@ -753,6 +758,11 @@ module ActiveRecord source_type = @prev_reflection.options[:source_type] lambda { |object| where(type => source_type) } end + + def alias_name(name, alias_tracker) + alias_name = "#{plural_name}_#{name}" + alias_tracker.aliased_table_for(table_name, alias_name) + end end # Consider the following example: -- cgit v1.2.3 From 092171da306609127dc50e7f45edadf4b27bc65d Mon Sep 17 00:00:00 2001 From: eileencodes Date: Thu, 6 Nov 2014 19:05:12 -0500 Subject: Clean up assignments in `#add_constraints` `is_first_chain`, `items` and `klass` are no longer beneficial and can be called directly instead of via their assignments - because they are each only used once. --- .../lib/active_record/associations/association_scope.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 4907d1cf6c..b5a6954554 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -187,21 +187,16 @@ module ActiveRecord scope = next_chain_scope(scope, table, reflection, connection, assoc_klass, foreign_table, next_reflection) end - is_first_chain = i == 0 - klass = is_first_chain ? assoc_klass : reflection.klass - - items = reflection.constraints - # Exclude the scope of the association itself, because that # was already merged in the #scope method. - items.each do |scope_chain_item| - item = eval_scope(klass, scope_chain_item, owner) + reflection.constraints.each do |scope_chain_item| + item = eval_scope(reflection.klass, scope_chain_item, owner) if scope_chain_item == refl.scope scope.merge! item.except(:where, :includes, :bind) end - if is_first_chain + if i == 0 scope.includes! item.includes_values end -- cgit v1.2.3 From 5b0b3cce5c0ecef02f1f6f09aea1de44b9ca88cf Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 11 Nov 2014 14:10:42 -0500 Subject: Move `#alias_name` to `ReflectionProxy` class Putting the `#alias_name` into ReflectionProxy means we don't have to cache the `#alias_name` globally anymore - it's not cached per query. --- .../associations/association_scope.rb | 33 +++++++++++++++------- activerecord/lib/active_record/reflection.rb | 10 ------- 2 files changed, 23 insertions(+), 20 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index b5a6954554..48288496c4 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -159,32 +159,45 @@ module ActiveRecord end def alias_name(name, alias_tracker) - alias_name = "#{plural_name}_#{name}_join" - table_name = klass.table_name - alias_tracker.aliased_table_for(table_name, alias_name) + @alias ||= begin + alias_name = "#{plural_name}_#{name}_join" + table_name = klass.table_name + alias_tracker.aliased_table_for(table_name, alias_name) + end + end + end + + class ReflectionProxy < SimpleDelegator + def alias_name(name, alias_tracker) + @alias ||= begin + alias_name = "#{plural_name}_#{name}" + alias_tracker.aliased_table_for(table_name, alias_name) + end end end def get_chain(reflection, association) - chain = reflection.chain.dup + chain = reflection.chain.map { |reflection| + ReflectionProxy.new(reflection) + } chain[0] = RuntimeReflection.new(reflection, association) chain end def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) - tables = construct_tables(chain, tracker, refl.name) - + construct_tables(chain, tracker, refl.name) owner_reflection = chain.last - table = tables.last - scope = last_chain_scope(scope, table, owner_reflection, owner, connection, assoc_klass) + table = owner_reflection.alias_name(refl.name, tracker) + scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) # chain.first always == refl chain.each_with_index do |reflection, i| - table, foreign_table = tables.shift, tables.first + table = reflection.alias_name(refl.name, tracker) unless reflection == chain.last next_reflection = chain[i + 1] - scope = next_chain_scope(scope, table, reflection, connection, assoc_klass, foreign_table, next_reflection) + foreign_table = next_reflection.alias_name(refl.name, tracker) + scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection) end # Exclude the scope of the association itself, because that diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 83771bd5dc..1bc92b1587 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -165,11 +165,6 @@ module ActiveRecord def constraints scope ? [scope] : [] end - - def alias_name(name, alias_tracker) - alias_name = "#{plural_name}_#{name}" - alias_tracker.aliased_table_for(table_name, alias_name) - end end # Base class for AggregateReflection and AssociationReflection. Objects of @@ -758,11 +753,6 @@ module ActiveRecord source_type = @prev_reflection.options[:source_type] lambda { |object| where(type => source_type) } end - - def alias_name(name, alias_tracker) - alias_name = "#{plural_name}_#{name}" - alias_tracker.aliased_table_for(table_name, alias_name) - end end # Consider the following example: -- cgit v1.2.3 From 17f6ca1e8a69f08a14fd7ab23dfe63691cd976a7 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 11 Nov 2014 14:34:08 -0500 Subject: Refactor `#get_chain` to remove need for `#construct_tables` By concatnating the `ReflectionProxy` with the `chain` we remove the need for `#construct_tables` because the `chain` is now in the correct order (order of the chain DOES matter). --- .../associations/association_scope.rb | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 48288496c4..5268fb2ac8 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -34,7 +34,7 @@ module ActiveRecord scope = klass.unscoped owner = association.owner alias_tracker = AliasTracker.empty connection - chain = get_chain(reflection, association) + chain = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) add_constraints(scope, owner, klass, reflection, alias_tracker, chain) @@ -62,13 +62,6 @@ module ActiveRecord end private - - def construct_tables(chain, alias_tracker, name) - chain.map do |reflection| - reflection.alias_name(name, alias_tracker) - end - end - def join(table, constraint) table.create_join(table, table.create_on(constraint), join_type) end @@ -176,16 +169,20 @@ module ActiveRecord end end - def get_chain(reflection, association) - chain = reflection.chain.map { |reflection| - ReflectionProxy.new(reflection) + def get_chain(refl, association, tracker) + name = refl.name + runtime_reflection = RuntimeReflection.new(refl, association) + runtime_reflection.alias_name(name, tracker) + chain = [runtime_reflection] + chain.concat refl.chain.drop(1).map { |reflection| + proxy = ReflectionProxy.new(reflection) + proxy.alias_name(name, tracker) + proxy } - chain[0] = RuntimeReflection.new(reflection, association) chain end def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) - construct_tables(chain, tracker, refl.name) owner_reflection = chain.last table = owner_reflection.alias_name(refl.name, tracker) scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) @@ -209,7 +206,7 @@ module ActiveRecord scope.merge! item.except(:where, :includes, :bind) end - if i == 0 + if reflection == chain.first scope.includes! item.includes_values end -- cgit v1.2.3 From 4d27d56c3547e57bc509980eb6a9b14c39488c46 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 24 Nov 2014 14:07:52 -0500 Subject: Refactor `#get_chain` iteration to a linked list The linked list lets us use a loop in `#add_constraints` and completely remove the need for indexing the iteration becasue we have access to the next item in the chain. --- .../associations/association_scope.rb | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 5268fb2ac8..cc6d23e80a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -33,11 +33,11 @@ module ActiveRecord reflection = association.reflection scope = klass.unscoped owner = association.owner - alias_tracker = AliasTracker.empty connection - chain = get_chain(reflection, association, alias_tracker) + alias_tracker = AliasTracker.create connection, association.klass.table_name + chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) - add_constraints(scope, owner, klass, reflection, alias_tracker, chain) + add_constraints(scope, owner, klass, reflection, alias_tracker, chain_head, chain_tail) end def join_type @@ -114,6 +114,8 @@ module ActiveRecord end class RuntimeReflection + attr_accessor :next + def initialize(reflection, association) @reflection = reflection @association = association @@ -161,6 +163,8 @@ module ActiveRecord end class ReflectionProxy < SimpleDelegator + attr_accessor :next + def alias_name(name, alias_tracker) @alias ||= begin alias_name = "#{plural_name}_#{name}" @@ -173,26 +177,28 @@ module ActiveRecord name = refl.name runtime_reflection = RuntimeReflection.new(refl, association) runtime_reflection.alias_name(name, tracker) - chain = [runtime_reflection] - chain.concat refl.chain.drop(1).map { |reflection| + prev = runtime_reflection + refl.chain.drop(1).each { |reflection| proxy = ReflectionProxy.new(reflection) proxy.alias_name(name, tracker) - proxy + prev.next = proxy + prev = proxy } - chain + [runtime_reflection, prev] end - def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) - owner_reflection = chain.last + def add_constraints(scope, owner, assoc_klass, refl, tracker, chain_head, chain_tail) + owner_reflection = chain_tail table = owner_reflection.alias_name(refl.name, tracker) scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) - # chain.first always == refl - chain.each_with_index do |reflection, i| + reflection = chain_head + loop do + break unless reflection table = reflection.alias_name(refl.name, tracker) - unless reflection == chain.last - next_reflection = chain[i + 1] + unless reflection == chain_tail + next_reflection = reflection.next foreign_table = next_reflection.alias_name(refl.name, tracker) scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection) end @@ -206,7 +212,7 @@ module ActiveRecord scope.merge! item.except(:where, :includes, :bind) end - if reflection == chain.first + if reflection == chain_head scope.includes! item.includes_values end @@ -214,6 +220,7 @@ module ActiveRecord scope.bind_values += item.bind_values scope.order_values |= item.order_values end + reflection = reflection.next end scope -- cgit v1.2.3 From e9684d6c8849767ad38cb3cc76cb628252a67ed6 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 1 Dec 2014 18:44:51 -0500 Subject: Clean up / refactor new reflection classes Move `RuntimeReflection` and `PolymorphicReflect` into Reflection. This allows the methods to inherit from `ThroughReflection` and DRY up the methods by removing duplicates. --- .../associations/association_scope.rb | 51 +-------- activerecord/lib/active_record/reflection.rb | 117 +++++++++++++-------- 2 files changed, 76 insertions(+), 92 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index cc6d23e80a..949ba75b1b 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -113,55 +113,6 @@ module ActiveRecord scope = scope.joins(join(foreign_table, constraint)) end - class RuntimeReflection - attr_accessor :next - - def initialize(reflection, association) - @reflection = reflection - @association = association - end - - def klass - @association.klass - end - - def scope - @reflection.scope - end - - def table_name - klass.table_name - end - - def plural_name - @reflection.plural_name - end - - def join_keys(assoc_klass) - @reflection.join_keys(assoc_klass) - end - - def type - @reflection.type - end - - def constraints - @reflection.constraints - end - - def source_type_info - @reflection.source_type_info - end - - def alias_name(name, alias_tracker) - @alias ||= begin - alias_name = "#{plural_name}_#{name}_join" - table_name = klass.table_name - alias_tracker.aliased_table_for(table_name, alias_name) - end - end - end - class ReflectionProxy < SimpleDelegator attr_accessor :next @@ -175,7 +126,7 @@ module ActiveRecord def get_chain(refl, association, tracker) name = refl.name - runtime_reflection = RuntimeReflection.new(refl, association) + runtime_reflection = ActiveRecord::Reflection::RuntimeReflection.new(refl, association) runtime_reflection.alias_name(name, tracker) prev = runtime_reflection refl.chain.drop(1).each { |reflection| diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 1bc92b1587..ea469f881c 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -163,7 +163,7 @@ module ActiveRecord end def constraints - scope ? [scope] : [] + scope_chain.flatten end end @@ -714,47 +714,6 @@ module ActiveRecord end end - class PolymorphicReflection - def initialize(reflection, prev_reflection) - @reflection = reflection - @prev_reflection = prev_reflection - end - - def klass - @reflection.klass - end - - def scope - @reflection.scope - end - - def table_name - @reflection.table_name - end - - def plural_name - @reflection.plural_name - end - - def join_keys(assoc_klass) - @reflection.join_keys(assoc_klass) - end - - def type - @reflection.type - end - - def constraints - [source_type_info] - end - - def source_type_info - type = @prev_reflection.foreign_type - source_type = @prev_reflection.options[:source_type] - lambda { |object| where(type => source_type) } - end - end - # Consider the following example: # # class Person @@ -934,5 +893,79 @@ module ActiveRecord delegate(*delegate_methods, to: :delegate_reflection) end + + class PolymorphicReflection < ThroughReflection + def initialize(reflection, prev_reflection) + @reflection = reflection + @prev_reflection = prev_reflection + end + + def klass + @reflection.klass + end + + def scope + @reflection.scope + end + + def table_name + @reflection.table_name + end + + def plural_name + @reflection.plural_name + end + + def join_keys(assoc_klass) + @reflection.join_keys(assoc_klass) + end + + def type + @reflection.type + end + + def constraints + [source_type_info] + end + + def source_type_info + type = @prev_reflection.foreign_type + source_type = @prev_reflection.options[:source_type] + lambda { |object| where(type => source_type) } + end + end + + class RuntimeReflection < PolymorphicReflection + attr_accessor :next + + def initialize(reflection, association) + @reflection = reflection + @association = association + end + + def klass + @association.klass + end + + def table_name + klass.table_name + end + + def constraints + @reflection.constraints + end + + def source_type_info + @reflection.source_type_info + end + + def alias_name(name, alias_tracker) + @alias ||= begin + alias_name = "#{plural_name}_#{name}_join" + table_name = klass.table_name + alias_tracker.aliased_table_for(table_name, alias_name) + end + end + end end end -- cgit v1.2.3 From f6729309a06f40b32e52f8ee8143d1b1da412597 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 2 Dec 2014 19:03:25 -0500 Subject: Assign the `#alias_name` to each reflection This makes the `#alias_name` more functional. --- .../associations/association_scope.rb | 23 +++++++++++----------- activerecord/lib/active_record/reflection.rb | 10 +++------- 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 949ba75b1b..0fdb3737fd 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -114,24 +114,25 @@ module ActiveRecord end class ReflectionProxy < SimpleDelegator - attr_accessor :next + attr_accessor :next, :alias_name - def alias_name(name, alias_tracker) - @alias ||= begin - alias_name = "#{plural_name}_#{name}" - alias_tracker.aliased_table_for(table_name, alias_name) - end + def alias_candidate(name) + "#{plural_name}_#{name}" end end def get_chain(refl, association, tracker) name = refl.name runtime_reflection = ActiveRecord::Reflection::RuntimeReflection.new(refl, association) - runtime_reflection.alias_name(name, tracker) + alias_name = tracker.aliased_table_for(runtime_reflection.table_name, runtime_reflection.alias_candidate(name)) + runtime_reflection.alias_name = alias_name prev = runtime_reflection refl.chain.drop(1).each { |reflection| proxy = ReflectionProxy.new(reflection) - proxy.alias_name(name, tracker) + + alias_name = tracker.aliased_table_for(proxy.table_name, proxy.alias_candidate(name)) + proxy.alias_name = alias_name + prev.next = proxy prev = proxy } @@ -140,17 +141,17 @@ module ActiveRecord def add_constraints(scope, owner, assoc_klass, refl, tracker, chain_head, chain_tail) owner_reflection = chain_tail - table = owner_reflection.alias_name(refl.name, tracker) + table = owner_reflection.alias_name scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) reflection = chain_head loop do break unless reflection - table = reflection.alias_name(refl.name, tracker) + table = reflection.alias_name unless reflection == chain_tail next_reflection = reflection.next - foreign_table = next_reflection.alias_name(refl.name, tracker) + foreign_table = next_reflection.alias_name scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection) end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index ea469f881c..79c6504a18 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -936,7 +936,7 @@ module ActiveRecord end class RuntimeReflection < PolymorphicReflection - attr_accessor :next + attr_accessor :next, :alias_name def initialize(reflection, association) @reflection = reflection @@ -959,12 +959,8 @@ module ActiveRecord @reflection.source_type_info end - def alias_name(name, alias_tracker) - @alias ||= begin - alias_name = "#{plural_name}_#{name}_join" - table_name = klass.table_name - alias_tracker.aliased_table_for(table_name, alias_name) - end + def alias_candidate(name) + "#{plural_name}_#{name}_join" end end end -- cgit v1.2.3 From cc9b813a821ef90d96405bf618fd691522a11ef9 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 9 Dec 2014 13:56:52 -0500 Subject: Pass `connection` rather than `alias_tracker` After the refactorings we're only using the connection and not the alias tracker anymore. This builds on commit 18019. Reuse the already available `@connection` to reduce the surface area of the alias tracker's API. We can then remove the `attr_reader` because the connection is already available. --- activerecord/lib/active_record/associations/alias_tracker.rb | 6 +++--- activerecord/lib/active_record/associations/association_scope.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index f9c9f8afda..27d918696a 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -5,7 +5,7 @@ module ActiveRecord # Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency and # ActiveRecord::Associations::ThroughAssociationScope class AliasTracker # :nodoc: - attr_reader :aliases, :connection + attr_reader :aliases def self.empty(connection) new connection, Hash.new(0) @@ -63,7 +63,7 @@ module ActiveRecord Arel::Table.new(table_name, table_options) else # Otherwise, we need to use an alias - aliased_name = connection.table_alias_for(aliased_name) + aliased_name = @connection.table_alias_for(aliased_name) # Update the count aliases[aliased_name] += 1 @@ -80,7 +80,7 @@ module ActiveRecord private def truncate(name) - name.slice(0, connection.table_alias_length - 2) + name.slice(0, @connection.table_alias_length - 2) end end end diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 0fdb3737fd..198a047e18 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -37,7 +37,7 @@ module ActiveRecord chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) - add_constraints(scope, owner, klass, reflection, alias_tracker, chain_head, chain_tail) + add_constraints(scope, owner, klass, reflection, connection, chain_head, chain_tail) end def join_type @@ -139,10 +139,10 @@ module ActiveRecord [runtime_reflection, prev] end - def add_constraints(scope, owner, assoc_klass, refl, tracker, chain_head, chain_tail) + def add_constraints(scope, owner, assoc_klass, refl, connection, chain_head, chain_tail) owner_reflection = chain_tail table = owner_reflection.alias_name - scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) + scope = last_chain_scope(scope, table, owner_reflection, owner, connection, assoc_klass) reflection = chain_head loop do @@ -152,7 +152,7 @@ module ActiveRecord unless reflection == chain_tail next_reflection = reflection.next foreign_table = next_reflection.alias_name - scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection) + scope = next_chain_scope(scope, table, reflection, connection, assoc_klass, foreign_table, next_reflection) end # Exclude the scope of the association itself, because that -- cgit v1.2.3 From 16fafd658805407e2bda4f4bb06a70157c21f78a Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 9 Dec 2014 14:29:50 -0500 Subject: Move `alias_candiate` into `AbstractReflection` This moves `alias_candidate` out of the `ReflectionProxy` and into the `AbstractReflection` so it is shared by all reflections. Change `alias_name` to a method and and remove assignment in `#get_chain`. --- .../lib/active_record/associations/association_scope.rb | 16 +++++++--------- activerecord/lib/active_record/reflection.rb | 10 +++++++++- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 198a047e18..9d94822fc5 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -114,10 +114,12 @@ module ActiveRecord end class ReflectionProxy < SimpleDelegator - attr_accessor :next, :alias_name + attr_accessor :next + attr_reader :alias_name - def alias_candidate(name) - "#{plural_name}_#{name}" + def initialize(reflection, alias_name) + super(reflection) + @alias_name = alias_name end end @@ -125,14 +127,10 @@ module ActiveRecord name = refl.name runtime_reflection = ActiveRecord::Reflection::RuntimeReflection.new(refl, association) alias_name = tracker.aliased_table_for(runtime_reflection.table_name, runtime_reflection.alias_candidate(name)) - runtime_reflection.alias_name = alias_name prev = runtime_reflection refl.chain.drop(1).each { |reflection| - proxy = ReflectionProxy.new(reflection) - - alias_name = tracker.aliased_table_for(proxy.table_name, proxy.alias_candidate(name)) - proxy.alias_name = alias_name - + alias_name = tracker.aliased_table_for(reflection.table_name, reflection.alias_candidate(name)) + proxy = ReflectionProxy.new(reflection, alias_name) prev.next = proxy prev = proxy } diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 79c6504a18..111911b575 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -165,6 +165,10 @@ module ActiveRecord def constraints scope_chain.flatten end + + def alias_candidate(name) + "#{plural_name}_#{name}" + end end # Base class for AggregateReflection and AssociationReflection. Objects of @@ -936,7 +940,7 @@ module ActiveRecord end class RuntimeReflection < PolymorphicReflection - attr_accessor :next, :alias_name + attr_accessor :next def initialize(reflection, association) @reflection = reflection @@ -962,6 +966,10 @@ module ActiveRecord def alias_candidate(name) "#{plural_name}_#{name}_join" end + + def alias_name + Arel::Table.new(table_name) + end end end end -- cgit v1.2.3 From 0408e212ca224bb25159f3e6db2a9c64cdea1200 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 16 Dec 2014 14:26:45 -0500 Subject: Initialze `#alias_tracker` with base table name Instead of initializing an empty connection use the base table name instead. Split up and refactor `#create` to be 2 methods `#create` and `#create_with_joins`. Removes the need to update the count by 1 on initialzing a JoinDependency. --- .../lib/active_record/associations/alias_tracker.rb | 19 +++++++++++-------- .../active_record/associations/association_scope.rb | 1 - .../lib/active_record/associations/join_dependency.rb | 3 +-- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 27d918696a..36e62fe6b1 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -7,18 +7,21 @@ module ActiveRecord class AliasTracker # :nodoc: attr_reader :aliases - def self.empty(connection) - new connection, Hash.new(0) + def self.create(connection, initial_table) + aliases = Hash.new(0) + aliases[initial_table] = 1 + new connection, aliases end - def self.create(connection, table_joins) - if table_joins.empty? - empty connection + def self.create_with_joins(connection, initial_table, joins, type_caster) + if joins.empty? + create(connection, initial_table, type_caster) else - aliases = Hash.new { |h,k| - h[k] = initial_count_for(connection, k, table_joins) + aliases = Hash.new { |h, k| + h[k] = initial_count_for(connection, k, joins) } - new connection, aliases + aliases[initial_table] = 1 + new connection, aliases, type_caster end end diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 9d94822fc5..1f77a083aa 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -126,7 +126,6 @@ module ActiveRecord def get_chain(refl, association, tracker) name = refl.name runtime_reflection = ActiveRecord::Reflection::RuntimeReflection.new(refl, association) - alias_name = tracker.aliased_table_for(runtime_reflection.table_name, runtime_reflection.alias_candidate(name)) prev = runtime_reflection refl.chain.drop(1).each { |reflection| alias_name = tracker.aliased_table_for(reflection.table_name, reflection.alias_candidate(name)) diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 66e997c3c8..634abfac96 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -93,8 +93,7 @@ module ActiveRecord # joins # => [] # def initialize(base, associations, joins) - @alias_tracker = AliasTracker.create(base.connection, joins) - @alias_tracker.aliased_table_for(base.table_name, base.table_name, type_caster: base.type_caster) # Updates the count for base.table_name to 1 + @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins) tree = self.class.make_tree associations @join_root = JoinBase.new base, build(tree, base) @join_root.children.each { |child| construct_tables! @join_root, child } -- cgit v1.2.3 From 96e277c03b7e62e33858ea9e254c9ed88625778f Mon Sep 17 00:00:00 2001 From: eileencodes Date: Sun, 21 Dec 2014 17:51:16 -0500 Subject: Add `#all_includes` method to reflections `yield` instead of relying on checking if the reflection is equal to the `chain_head`. --- activerecord/lib/active_record/associations/association_scope.rb | 4 +++- activerecord/lib/active_record/reflection.rb | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 1f77a083aa..4fa227342f 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -121,6 +121,8 @@ module ActiveRecord super(reflection) @alias_name = alias_name end + + def all_includes; nil; end end def get_chain(refl, association, tracker) @@ -161,7 +163,7 @@ module ActiveRecord scope.merge! item.except(:where, :includes, :bind) end - if reflection == chain_head + reflection.all_includes do scope.includes! item.includes_values end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 111911b575..25fda8f110 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -970,6 +970,8 @@ module ActiveRecord def alias_name Arel::Table.new(table_name) end + + def all_includes; yield; end end end end -- cgit v1.2.3 From 39abe8355a56992b32ed95e1ea1eb588c0ad7a6f Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 29 Dec 2014 14:12:39 -0500 Subject: Move `#type_caster` to alias tracker initialize This moves the `#type_caster` from the `aliased_table_for` and into the initialize of the `alias_tracker`. --- .../lib/active_record/associations/alias_tracker.rb | 13 +++++++------ .../lib/active_record/associations/association_scope.rb | 2 +- .../lib/active_record/associations/join_dependency.rb | 8 ++------ 3 files changed, 10 insertions(+), 13 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 36e62fe6b1..2b7e4f28c5 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -7,10 +7,10 @@ module ActiveRecord class AliasTracker # :nodoc: attr_reader :aliases - def self.create(connection, initial_table) + def self.create(connection, initial_table, type_caster) aliases = Hash.new(0) aliases[initial_table] = 1 - new connection, aliases + new connection, aliases, type_caster end def self.create_with_joins(connection, initial_table, joins, type_caster) @@ -54,16 +54,17 @@ module ActiveRecord end # table_joins is an array of arel joins which might conflict with the aliases we assign here - def initialize(connection, aliases) + def initialize(connection, aliases, type_caster) @aliases = aliases @connection = connection + @type_caster = type_caster end - def aliased_table_for(table_name, aliased_name, **table_options) + def aliased_table_for(table_name, aliased_name) if aliases[table_name].zero? # If it's zero, we can have our table_name aliases[table_name] = 1 - Arel::Table.new(table_name, table_options) + Arel::Table.new(table_name, type_caster: @type_caster) else # Otherwise, we need to use an alias aliased_name = @connection.table_alias_for(aliased_name) @@ -76,7 +77,7 @@ module ActiveRecord else aliased_name end - Arel::Table.new(table_name, table_options).alias(table_alias) + Arel::Table.new(table_name, type_caster: @type_caster).alias(table_alias) end end diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 4fa227342f..170ae58b9f 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -33,7 +33,7 @@ module ActiveRecord reflection = association.reflection scope = klass.unscoped owner = association.owner - alias_tracker = AliasTracker.create connection, association.klass.table_name + alias_tracker = AliasTracker.create connection, association.klass.table_name, klass.type_caster chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 634abfac96..4b75370171 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -93,7 +93,7 @@ module ActiveRecord # joins # => [] # def initialize(base, associations, joins) - @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins) + @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins, base.type_caster) tree = self.class.make_tree associations @join_root = JoinBase.new base, build(tree, base) @join_root.children.each { |child| construct_tables! @join_root, child } @@ -185,13 +185,9 @@ module ActiveRecord def table_aliases_for(parent, node) node.reflection.chain.map { |reflection| - if reflection.klass - type_caster = reflection.klass.type_caster - end alias_tracker.aliased_table_for( reflection.table_name, - table_alias_for(reflection, parent, reflection != node.reflection), - type_caster: type_caster, + table_alias_for(reflection, parent, reflection != node.reflection) ) } end -- cgit v1.2.3 From b0d87a725af7d2c1e254780fa1052b210bcdec8c Mon Sep 17 00:00:00 2001 From: eileencodes Date: Wed, 31 Dec 2014 14:56:40 -0500 Subject: Cleanup methods, missing spacing and missing nodocs Add missing nodoc's Change `assoc_klass` argument name to `association_klass` Change `prev_reflection` argument name to `previous_reflection` Change `prev` to `previous_reflection` in `#get_chain` Switch use of `refl` and `reflection` in `#get_chain` so main parameter is not abbreviated. Add missing space in `#add_constraints` --- .../associations/association_scope.rb | 39 +++++++++++----------- activerecord/lib/active_record/reflection.rb | 28 ++++++++-------- 2 files changed, 34 insertions(+), 33 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 170ae58b9f..d06b7b3508 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -80,8 +80,8 @@ module ActiveRecord bind_value scope, column, value, connection end - def last_chain_scope(scope, table, reflection, owner, connection, assoc_klass) - join_keys = reflection.join_keys(assoc_klass) + def last_chain_scope(scope, table, reflection, owner, connection, association_klass) + join_keys = reflection.join_keys(association_klass) key = join_keys.key foreign_key = join_keys.foreign_key @@ -97,8 +97,8 @@ module ActiveRecord end end - def next_chain_scope(scope, table, reflection, connection, assoc_klass, foreign_table, next_reflection) - join_keys = reflection.join_keys(assoc_klass) + def next_chain_scope(scope, table, reflection, connection, association_klass, foreign_table, next_reflection) + join_keys = reflection.join_keys(association_klass) key = join_keys.key foreign_key = join_keys.foreign_key @@ -113,7 +113,7 @@ module ActiveRecord scope = scope.joins(join(foreign_table, constraint)) end - class ReflectionProxy < SimpleDelegator + class ReflectionProxy < SimpleDelegator # :nodoc: attr_accessor :next attr_reader :alias_name @@ -125,23 +125,23 @@ module ActiveRecord def all_includes; nil; end end - def get_chain(refl, association, tracker) - name = refl.name - runtime_reflection = ActiveRecord::Reflection::RuntimeReflection.new(refl, association) - prev = runtime_reflection - refl.chain.drop(1).each { |reflection| - alias_name = tracker.aliased_table_for(reflection.table_name, reflection.alias_candidate(name)) - proxy = ReflectionProxy.new(reflection, alias_name) - prev.next = proxy - prev = proxy - } - [runtime_reflection, prev] + def get_chain(reflection, association, tracker) + name = reflection.name + runtime_reflection = Reflection::RuntimeReflection.new(reflection, association) + previous_reflection = runtime_reflection + reflection.chain.drop(1).each do |refl| + alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name)) + proxy = ReflectionProxy.new(refl, alias_name) + previous_reflection.next = proxy + previous_reflection = proxy + end + [runtime_reflection, previous_reflection] end - def add_constraints(scope, owner, assoc_klass, refl, connection, chain_head, chain_tail) + def add_constraints(scope, owner, association_klass, refl, connection, chain_head, chain_tail) owner_reflection = chain_tail table = owner_reflection.alias_name - scope = last_chain_scope(scope, table, owner_reflection, owner, connection, assoc_klass) + scope = last_chain_scope(scope, table, owner_reflection, owner, connection, association_klass) reflection = chain_head loop do @@ -151,7 +151,7 @@ module ActiveRecord unless reflection == chain_tail next_reflection = reflection.next foreign_table = next_reflection.alias_name - scope = next_chain_scope(scope, table, reflection, connection, assoc_klass, foreign_table, next_reflection) + scope = next_chain_scope(scope, table, reflection, connection, association_klass, foreign_table, next_reflection) end # Exclude the scope of the association itself, because that @@ -171,6 +171,7 @@ module ActiveRecord scope.bind_values += item.bind_values scope.order_values |= item.order_values end + reflection = reflection.next end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 25fda8f110..7696ef13c7 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -149,7 +149,7 @@ module ActiveRecord JoinKeys = Struct.new(:key, :foreign_key) # :nodoc: - def join_keys(assoc_klass) + def join_keys(association_klass) JoinKeys.new(foreign_key, active_record_primary_key) end @@ -610,8 +610,8 @@ module ActiveRecord def belongs_to?; true; end - def join_keys(assoc_klass) - key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key + def join_keys(association_klass) + key = polymorphic? ? association_primary_key(association_klass) : association_primary_key JoinKeys.new(key, foreign_key) end @@ -706,7 +706,7 @@ module ActiveRecord def chain @chain ||= begin a = source_reflection.chain - b = through_reflection.chain.map(&:dup) + b = through_reflection.chain if options[:source_type] b[0] = PolymorphicReflection.new(b[0], self) @@ -759,8 +759,8 @@ module ActiveRecord end end - def join_keys(assoc_klass) - source_reflection.join_keys(assoc_klass) + def join_keys(association_klass) + source_reflection.join_keys(association_klass) end # The macro used by the source association @@ -898,10 +898,10 @@ module ActiveRecord end - class PolymorphicReflection < ThroughReflection - def initialize(reflection, prev_reflection) + class PolymorphicReflection < ThroughReflection # :nodoc: + def initialize(reflection, previous_reflection) @reflection = reflection - @prev_reflection = prev_reflection + @previous_reflection = previous_reflection end def klass @@ -920,8 +920,8 @@ module ActiveRecord @reflection.plural_name end - def join_keys(assoc_klass) - @reflection.join_keys(assoc_klass) + def join_keys(association_klass) + @reflection.join_keys(association_klass) end def type @@ -933,13 +933,13 @@ module ActiveRecord end def source_type_info - type = @prev_reflection.foreign_type - source_type = @prev_reflection.options[:source_type] + type = @previous_reflection.foreign_type + source_type = @previous_reflection.options[:source_type] lambda { |object| where(type => source_type) } end end - class RuntimeReflection < PolymorphicReflection + class RuntimeReflection < PolymorphicReflection # :nodoc: attr_accessor :next def initialize(reflection, association) -- cgit v1.2.3