diff options
5 files changed, 43 insertions, 8 deletions
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index cead614d0f..358db6df1d 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -21,7 +21,7 @@ module ActiveRecord construct_sql end - delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :from, :lock, :readonly, :having, :to => :scoped + delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :to => :scoped def select(select = nil, &block) if block_given? diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e77cc6e697..b0bc7b928e 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -655,7 +655,7 @@ module ActiveRecord #:nodoc: end end - delegate :select, :group, :order, :limit, :joins, :where, :preload, :eager_load, :from, :lock, :readonly, :having, :to => :scoped + delegate :select, :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :to => :scoped # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the # same arguments to this method as you can to <tt>find(:first)</tt>. diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index b445ba67b7..fc4d1a6960 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -5,13 +5,15 @@ module ActiveRecord delegate :to_sql, :to => :relation delegate :length, :collect, :map, :each, :all?, :to => :to_a - attr_reader :relation, :klass, :preload_associations, :eager_load_associations - attr_writer :readonly, :preload_associations, :eager_load_associations, :table + attr_reader :relation, :klass + attr_writer :readonly, :table + attr_accessor :preload_associations, :eager_load_associations, :include_associations def initialize(klass, relation) @klass, @relation = klass, relation @preload_associations = [] @eager_load_associations = [] + @include_associations = [] @loaded, @readonly = false end @@ -30,7 +32,7 @@ module ActiveRecord def merge(r) raise ArgumentError, "Cannot merge a #{r.klass.name} relation with #{@klass.name} relation" if r.klass != @klass - merged_relation = spawn(table).eager_load(r.eager_load_associations).preload(r.preload_associations) + merged_relation = spawn(table).eager_load(r.eager_load_associations).preload(r.preload_associations).includes(r.include_associations) merged_relation.readonly = r.readonly [self.relation, r.relation].each do |arel| @@ -74,7 +76,9 @@ module ActiveRecord def to_a return @records if loaded? - @records = if @eager_load_associations.any? + find_with_associations = @eager_load_associations.any? + + @records = if find_with_associations begin @klass.send(:find_with_associations, { :select => @relation.send(:select_clauses).join(', '), @@ -94,7 +98,10 @@ module ActiveRecord @klass.find_by_sql(@relation.to_sql) end - @preload_associations.each {|associations| @klass.send(:preload_associations, @records, associations) } + preload = @preload_associations + preload += @include_associations unless find_with_associations + preload.each {|associations| @klass.send(:preload_associations, @records, associations) } + @records.each { |record| record.readonly! } if @readonly @loaded = true @@ -160,6 +167,7 @@ module ActiveRecord relation.readonly = @readonly relation.preload_associations = @preload_associations relation.eager_load_associations = @eager_load_associations + relation.include_associations = @include_associations relation.table = table relation end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 4600aab574..cf2cc7ba70 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -5,6 +5,10 @@ module ActiveRecord spawn.tap {|r| r.preload_associations += Array.wrap(associations) } end + def includes(*associations) + spawn.tap {|r| r.include_associations += Array.wrap(associations) } + end + def eager_load(*associations) spawn.tap {|r| r.eager_load_associations += Array.wrap(associations) } end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index bea2946130..18f6152cc0 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -178,7 +178,7 @@ class RelationTest < ActiveRecord::TestCase end end - def test_find_with_included_associations + def test_find_with_preloaded_associations assert_queries(2) do posts = Post.preload(:comments) assert posts.first.comments.first @@ -206,6 +206,29 @@ class RelationTest < ActiveRecord::TestCase end end + def test_find_with_included_associations + assert_queries(2) do + posts = Post.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.scoped.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.includes(:author) + assert posts.first.author + end + + assert_queries(3) do + posts = Post.includes(:author, :comments).to_a + assert posts.first.author + assert posts.first.comments.first + end + end + def test_default_scope_with_conditions_string assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort assert_equal nil, DeveloperCalledDavid.create!.name |