Permalink
Browse files

Merge pull request #14573 from habermann24/has_many_through_fix

Properly handle scoping with has_many :through. Fixes #14537.

Conflicts:
	activerecord/CHANGELOG.md
	activerecord/test/cases/associations/has_many_through_associations_test.rb

Conflicts:
	activerecord/CHANGELOG.md
  • Loading branch information...
1 parent 3601932 commit c35e438620f2d56562251571377995359546393d Rafael Mendonça França committed Apr 22, 2014
@@ -1,3 +1,12 @@
+* Fixed unexpected behavior for `has_many :through` associations going through a scoped `has_many`.
+
+ If a `has_many` association is adjusted using a scope, and another `has_many :through`
+ uses this association, then the scope adjustment is unexpectedly neglected.
+
+ Fixes #14537.
+
+ *Jan Habermann*
+
* When a destroyed record is duped, the dup is not `destroyed?`.
*Kuldeep Aggarwal*
@@ -14,9 +14,11 @@ module ThroughAssociation #:nodoc:
def target_scope
scope = super
chain.drop(1).each do |reflection|
+ relation = reflection.klass.all
+ relation.merge!(reflection.scope) if reflection.scope
+
scope.merge!(
- reflection.klass.all.
- except(:select, :create_with, :includes, :preload, :joins, :eager_load)
+ relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
)
end
scope
@@ -1116,5 +1116,16 @@ def test_has_many_through_obeys_order_on_through_association
club.reload
assert_equal [member], club.favourites
+
+ def test_has_many_through_unscope_default_scope
+ post = Post.create!(:title => 'Beaches', :body => "I like beaches!")
+ Reader.create! :person => people(:david), :post => post
+ LazyReader.create! :person => people(:susan), :post => post
+
+ assert_equal 2, post.people.to_a.size
+ assert_equal 1, post.lazy_people.to_a.size
+
+ assert_equal 2, post.lazy_readers_unscope_skimmers.to_a.size
+ assert_equal 2, post.lazy_people_unscope_skimmers.to_a.size
end
end
@@ -145,6 +145,10 @@ def add_joins_and_select
has_many :lazy_readers
has_many :lazy_readers_skimmers_or_not, -> { where(skimmer: [ true, false ]) }, :class_name => 'LazyReader'
+ has_many :lazy_people, :through => :lazy_readers, :source => :person
+ has_many :lazy_readers_unscope_skimmers, -> { skimmers_or_not }, :class_name => 'LazyReader'
+ has_many :lazy_people_unscope_skimmers, :through => :lazy_readers_unscope_skimmers, :source => :person
+
def self.top(limit)
ranked_by_comments.limit_by(limit)
end
@@ -16,6 +16,8 @@ class LazyReader < ActiveRecord::Base
self.table_name = "readers"
default_scope -> { where(skimmer: true) }
+ scope :skimmers_or_not, -> { unscope(:where => :skimmer) }
+
belongs_to :post
belongs_to :person
end

0 comments on commit c35e438

Please sign in to comment.