aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorErnie Miller <ernie@metautonomo.us>2010-10-20 22:54:43 -0400
committerAaron Patterson <aaron.patterson@gmail.com>2010-10-30 06:48:44 -0700
commit0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f (patch)
treece704699ba926f315a080963f4d094d44ee60cf0 /activerecord/lib
parentb82fab25f999dd6245c23a22f948048eef2d5d9a (diff)
downloadrails-0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f.tar.gz
rails-0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f.tar.bz2
rails-0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f.zip
Fix issues when including the same association multiple times and mixing joins/includes together.
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations.rb48
1 files changed, 37 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 59d328f207..b8cd2aa31e 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1837,7 +1837,7 @@ module ActiveRecord
def initialize(base, associations, joins)
@join_parts = [JoinBase.new(base, joins)]
- @associations = associations
+ @associations = {}
@reflections = []
@base_records_hash = {}
@base_records_in_order = []
@@ -1917,30 +1917,57 @@ module ActiveRecord
protected
+ def cache_joined_association(association)
+ associations = []
+ parent = association.parent
+ while parent != join_base
+ associations.unshift(parent.reflection.name)
+ parent = parent.parent
+ end
+ ref = @associations
+ associations.each do |key|
+ ref = ref[key]
+ end
+ ref[association.reflection.name] ||= {}
+ end
+
def build(associations, parent = nil, join_type = Arel::InnerJoin)
parent ||= join_parts.last
case associations
when Symbol, String
reflection = parent.reflections[associations.to_s.intern] or
raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
- @reflections << reflection
- join_association = build_join_association(reflection, parent)
- join_association.join_type = join_type
- @join_parts << join_association
+ unless join_association = find_join_association(reflection, parent)
+ @reflections << reflection
+ join_association = build_join_association(reflection, parent)
+ join_association.join_type = join_type
+ @join_parts << join_association
+ cache_joined_association(join_association)
+ end
+ join_association
when Array
associations.each do |association|
build(association, parent, join_type)
end
when Hash
associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
- build(name, parent, join_type)
- build(associations[name], nil, join_type)
+ join_association = build(name, parent, join_type)
+ build(associations[name], join_association, join_type)
end
else
raise ConfigurationError, associations.inspect
end
end
+ def find_join_association(name_or_reflection, parent)
+ case name_or_reflection
+ when Symbol, String
+ join_associations.detect {|j| (j.reflection.name == name_or_reflection.to_s.intern) && (j.parent == parent)}
+ else
+ join_associations.detect {|j| (j.reflection == name_or_reflection) && (j.parent == parent)}
+ end
+ end
+
def remove_uniq_by_reflection(reflection, records)
if reflection && reflection.collection?
records.each { |record| record.send(reflection.name).target.uniq! }
@@ -2013,7 +2040,7 @@ module ActiveRecord
end
# A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
- # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
+ # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
# everything else is being joined onto. A JoinAssociation represents an association which
# is joining to the base. A JoinAssociation may result in more than one actual join
# operations (for example a has_and_belongs_to_many JoinAssociation would result in
@@ -2092,8 +2119,7 @@ module ActiveRecord
def ==(other)
other.class == self.class &&
- other.active_record == active_record &&
- other.table_joins == table_joins
+ other.active_record == active_record
end
def aliased_prefix
@@ -2114,7 +2140,7 @@ module ActiveRecord
attr_reader :reflection
# The JoinDependency object which this JoinAssociation exists within. This is mainly
- # relevant for generating aliases which do not conflict with other joins which are
+ # relevant for generating aliases which do not conflict with other joins which are
# part of the query.
attr_reader :join_dependency