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

Properly append preload / includes args on Merger

Couldn't find other way to get the association name from a given class
other than looping through `reflect_on_all_associations` reflections ..

Noticed this one while looking at this example:

```ruby
class Product < ActiveRecord::Base
  has_many :variants
  has_many :translations
end

class Translation < ActiveRecord::Base
  belongs_to :product
end

class Variant < ActiveRecord::Base
  belongs_to :product
end

class BugTest < Minitest::Test
  def test_merge_stuff
    product = Product.create! name: 'huhu'
    variant = Variant.create! product_id: product.id
    Translation.create! locale: 'en', product_id: product.id

    product_relation = Product.all
                              .preload(:translations)
                              .joins(:translations)
                              .merge(Translation.where(locale: 'en'))
                              .where(name: 'huhu')

    assert_equal variant, Variant.joins(:product).merge(product_relation).first
  end
end
```
This commit is contained in:
Washington Luiz 2015-05-19 00:18:44 -03:00
parent d0a370ec93
commit a01d164b94
2 changed files with 50 additions and 2 deletions

View file

@ -50,7 +50,7 @@ module ActiveRecord
NORMAL_VALUES = Relation::VALUE_METHODS - NORMAL_VALUES = Relation::VALUE_METHODS -
Relation::CLAUSE_METHODS - Relation::CLAUSE_METHODS -
[:joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc: [:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
def normal_values def normal_values
NORMAL_VALUES NORMAL_VALUES
@ -75,6 +75,7 @@ module ActiveRecord
merge_multi_values merge_multi_values
merge_single_values merge_single_values
merge_clauses merge_clauses
merge_preloads
merge_joins merge_joins
relation relation
@ -82,6 +83,27 @@ module ActiveRecord
private private
def merge_preloads
return if other.preload_values.empty? && other.includes_values.empty?
if other.klass == relation.klass
relation.preload! other.preload_values unless other.preload_values.empty?
relation.includes! other.includes_values unless other.includes_values.empty?
else
reflection = relation.klass.reflect_on_all_associations.find do |reflection|
reflection.class_name == other.klass.name
end || return
unless other.preload_values.empty?
relation.preload! reflection.name => other.preload_values
end
unless other.includes_values.empty?
relation.includes! reflection.name => other.includes_values
end
end
end
def merge_joins def merge_joins
return if other.joins_values.blank? return if other.joins_values.blank?

View file

@ -17,7 +17,7 @@ require 'models/tyre'
require 'models/minivan' require 'models/minivan'
require 'models/aircraft' require 'models/aircraft'
require "models/possession" require "models/possession"
require "models/reader"
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,
@ -621,6 +621,32 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 1, query.to_a.size assert_equal 1, query.to_a.size
end end
def test_preloading_with_associations_and_merges
post = Post.create! title: 'Uhuu', body: 'body'
reader = Reader.create! post_id: post.id, person_id: 1
comment = Comment.create! post_id: post.id, body: 'body'
assert !comment.respond_to?(:readers)
post_rel = Post.preload(:readers).joins(:readers).where(title: 'Uhuu')
result_comment = Comment.joins(:post).merge(post_rel).to_a.first
assert_equal comment, result_comment
assert_no_queries do
assert_equal post, result_comment.post
assert_equal [reader], result_comment.post.readers.to_a
end
post_rel = Post.includes(:readers).where(title: 'Uhuu')
result_comment = Comment.joins(:post).merge(post_rel).first
assert_equal comment, result_comment
assert_no_queries do
assert_equal post, result_comment.post
assert_equal [reader], result_comment.post.readers.to_a
end
end
def test_loading_with_one_association def test_loading_with_one_association
posts = Post.preload(:comments) posts = Post.preload(:comments)
post = posts.find { |p| p.id == 1 } post = posts.find { |p| p.id == 1 }