From 0d8cf53296a4d7c1e6d85c533784a2607bfe3baa Mon Sep 17 00:00:00 2001 From: Jared Armstrong Date: Sat, 17 Mar 2012 00:37:56 +1300 Subject: Allow ActiveRecord::Relation merges to maintain context of joined associations --- .../active_record/associations/join_dependency.rb | 2 +- .../join_dependency/join_association.rb | 7 ++++- activerecord/lib/active_record/relation/merger.rb | 31 +++++++++++++++++++--- activerecord/test/cases/relations_test.rb | 9 ++++++- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index cd366ac8b7..e3d8356f49 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -109,7 +109,7 @@ module ActiveRecord 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?" + raise ConfigurationError, "Association named '#{ associations }' was not found on #{parent.active_record.name}; perhaps you misspelled it?" unless join_association = find_join_association(reflection, parent) @reflections << reflection join_association = build_join_association(reflection, parent) diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index 0d7d28e458..ea4856408d 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -55,7 +55,12 @@ module ActiveRecord def find_parent_in(other_join_dependency) other_join_dependency.join_parts.detect do |join_part| - parent == join_part + case parent + when JoinBase + parent.active_record == join_part.active_record + else + parent == join_part + end end end diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 3f880ce5e9..c2f0a82fd3 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -29,7 +29,7 @@ module ActiveRecord end class Merger - attr_reader :relation, :values + attr_reader :relation, :other def initialize(relation, other) if other.default_scoped? && other.klass != relation.klass @@ -37,13 +37,17 @@ module ActiveRecord end @relation = relation - @values = other.values + @other = other + end + + def values + @other.values end def normal_values Relation::SINGLE_VALUE_METHODS + Relation::MULTI_VALUE_METHODS - - [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering] + [:where, :joins, :order, :bind, :reverse_order, :lock, :create_with, :reordering] end def merge @@ -54,6 +58,7 @@ module ActiveRecord merge_multi_values merge_single_values + merge_joins relation end @@ -84,6 +89,26 @@ module ActiveRecord end end + def merge_joins + return if values[:joins].blank? + + if other.klass == relation.klass + relation.joins!(values[:joins]) + else + joins_to_stash, other_joins = values[:joins].partition { |join| + case join + when Hash, Symbol, Array + true + else + false + end + } + + join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass, joins_to_stash, []) + relation.joins!(join_dependency.join_associations + other_joins) + end + end + def merged_binds if values[:bind] (relation.bind_values + values[:bind]).uniq(&:first) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 3ef357e297..48fc82bbc7 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -6,6 +6,7 @@ require 'models/topic' require 'models/comment' require 'models/author' require 'models/comment' +require 'models/rating' require 'models/entrant' require 'models/developer' require 'models/reply' @@ -19,7 +20,7 @@ require 'models/minivan' class RelationTest < ActiveRecord::TestCase fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, - :tags, :taggings, :cars, :minivans + :ratings, :tags, :taggings, :cars, :minivans def test_do_not_double_quote_string_id van = Minivan.last @@ -731,6 +732,12 @@ class RelationTest < ActiveRecord::TestCase assert_equal 1, comments.count end + def test_relation_merging_with_merged_joins + special_comments_with_ratings = SpecialComment.joins(:ratings) + posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) + assert_equal 1, authors(:david).posts.merge(posts_with_special_comments_with_ratings).to_a.length + end + def test_count posts = Post.scoped -- cgit v1.2.3