aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreileencodes <eileencodes@gmail.com>2014-10-18 14:53:21 -0400
committereileencodes <eileencodes@gmail.com>2015-01-02 17:15:30 -0500
commit08acb4bccba5b64a233eb7c2ea1b0cd09881d2cb (patch)
treeab8916e6923a4ca2c31db8dbbb0ad85f48cd5f5f
parent9b366b95f9aeb50388af6d247944ed63751b570a (diff)
downloadrails-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.rb7
-rw-r--r--activerecord/lib/active_record/reflection.rb59
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