From e6a68a5cc3b47865abbba59bf693215c50136002 Mon Sep 17 00:00:00 2001 From: Pratik Naik <pratiknaik@gmail.com> Date: Tue, 19 Jan 2010 04:32:40 +0530 Subject: Add Relation#find_with_associations to load relation with eager loaded associations --- activerecord/lib/active_record/relation.rb | 29 +++-------------- .../lib/active_record/relation/finder_methods.rb | 36 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 25 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 4ed118b02d..e37e692a97 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -45,33 +45,12 @@ module ActiveRecord def to_a return @records if loaded? - find_with_associations = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?) - - @records = if find_with_associations - begin - options = { - :select => @select_values.join(", "), - :joins => arel.joins(arel), - :group => @group_values.join(", "), - :order => @order_values.join(', '), - :conditions => where_clause, - :limit => @limit_value, - :offset => @offset_value, - :from => @from_value - } - - including = (@eager_load_values + @includes_values).uniq - join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil) - @klass.send(:find_with_associations, options, join_dependency) - rescue ThrowResult - [] - end - else - @klass.find_by_sql(arel.to_sql) - end + eager_loading = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?) + + @records = eager_loading ? find_with_associations : @klass.find_by_sql(arel.to_sql) preload = @preload_values - preload += @includes_values unless find_with_associations + preload += @includes_values unless eager_loading preload.each {|associations| @klass.send(:preload_associations, @records, associations) } # @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT. diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 3668b0997f..980c5796f3 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -44,6 +44,42 @@ module ActiveRecord protected + def find_with_associations + including = (@eager_load_values + @includes_values).uniq + join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil) + rows = construct_relation_for_association_find(join_dependency).to_a + join_dependency.instantiate(rows) + rescue ThrowResult + [] + end + + def construct_relation_for_association_find(join_dependency) + relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency)) + + for association in join_dependency.join_associations + relation = association.join_relation(relation) + end + + limitable_reflections = @klass.send(:using_limitable_reflections?, join_dependency.reflections) + + if !limitable_reflections && relation.limit_value + limited_id_condition = construct_limited_ids_condition(relation.except(:select)) + relation = relation.where(limited_id_condition) + end + + relation = relation.except(:limit, :offset) unless limitable_reflections + + relation + end + + def construct_limited_ids_condition(relation) + orders = relation.order_values.join(", ") + values = @klass.connection.distinct("#{@klass.connection.quote_table_name @klass.table_name}.#{@klass.primary_key}", orders) + + ids_array = relation.select(values).collect {|row| row[@klass.primary_key]} + ids_array.empty? ? raise(ThrowResult) : primary_key.in(ids_array) + end + def find_by_attributes(match, attributes, *args) conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h} result = where(conditions).send(match.finder) -- cgit v1.2.3