1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Allow ActiveRecord::Relation merges to maintain context of joined associations

This commit is contained in:
Jared Armstrong 2012-03-17 00:37:56 +13:00
parent 5f62c86b50
commit 0d8cf53296
4 changed files with 43 additions and 6 deletions

View file

@ -109,7 +109,7 @@ module ActiveRecord
case associations case associations
when Symbol, String when Symbol, String
reflection = parent.reflections[associations.to_s.intern] or 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) unless join_association = find_join_association(reflection, parent)
@reflections << reflection @reflections << reflection
join_association = build_join_association(reflection, parent) join_association = build_join_association(reflection, parent)

View file

@ -55,7 +55,12 @@ module ActiveRecord
def find_parent_in(other_join_dependency) def find_parent_in(other_join_dependency)
other_join_dependency.join_parts.detect do |join_part| 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
end end

View file

@ -29,7 +29,7 @@ module ActiveRecord
end end
class Merger class Merger
attr_reader :relation, :values attr_reader :relation, :other
def initialize(relation, other) def initialize(relation, other)
if other.default_scoped? && other.klass != relation.klass if other.default_scoped? && other.klass != relation.klass
@ -37,13 +37,17 @@ module ActiveRecord
end end
@relation = relation @relation = relation
@values = other.values @other = other
end
def values
@other.values
end end
def normal_values def normal_values
Relation::SINGLE_VALUE_METHODS + Relation::SINGLE_VALUE_METHODS +
Relation::MULTI_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 end
def merge def merge
@ -54,6 +58,7 @@ module ActiveRecord
merge_multi_values merge_multi_values
merge_single_values merge_single_values
merge_joins
relation relation
end end
@ -84,6 +89,26 @@ module ActiveRecord
end end
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 def merged_binds
if values[:bind] if values[:bind]
(relation.bind_values + values[:bind]).uniq(&:first) (relation.bind_values + values[:bind]).uniq(&:first)

View file

@ -6,6 +6,7 @@ require 'models/topic'
require 'models/comment' require 'models/comment'
require 'models/author' require 'models/author'
require 'models/comment' require 'models/comment'
require 'models/rating'
require 'models/entrant' require 'models/entrant'
require 'models/developer' require 'models/developer'
require 'models/reply' require 'models/reply'
@ -19,7 +20,7 @@ require 'models/minivan'
class RelationTest < ActiveRecord::TestCase class RelationTest < ActiveRecord::TestCase
fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, 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 def test_do_not_double_quote_string_id
van = Minivan.last van = Minivan.last
@ -731,6 +732,12 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 1, comments.count assert_equal 1, comments.count
end 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 def test_count
posts = Post.scoped posts = Post.scoped