diff options
author | eileencodes <eileencodes@gmail.com> | 2014-10-18 14:53:21 -0400 |
---|---|---|
committer | eileencodes <eileencodes@gmail.com> | 2015-01-02 17:15:30 -0500 |
commit | 08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb (patch) | |
tree | ab8916e6923a4ca2c31db8dbbb0ad85f48cd5f5f | |
parent | 9b366b95f9aeb50388af6d247944ed63751b570a (diff) | |
download | rails-08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb.tar.gz rails-08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb.tar.bz2 rails-08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb.zip |
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`
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 7 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 59 |
2 files changed, 62 insertions, 4 deletions
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 |