aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2010-01-19 04:32:40 +0530
committerPratik Naik <pratiknaik@gmail.com>2010-01-19 04:42:19 +0530
commite6a68a5cc3b47865abbba59bf693215c50136002 (patch)
tree3ed9fa1ae775083a1bf648519e69f6ee27795197 /activerecord/lib/active_record
parentf2693cda446dc039e52eee43b60346689850bb76 (diff)
downloadrails-e6a68a5cc3b47865abbba59bf693215c50136002.tar.gz
rails-e6a68a5cc3b47865abbba59bf693215c50136002.tar.bz2
rails-e6a68a5cc3b47865abbba59bf693215c50136002.zip
Add Relation#find_with_associations to load relation with eager loaded associations
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/relation.rb29
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb36
2 files changed, 40 insertions, 25 deletions
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)