diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2019-04-05 12:51:13 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2019-04-05 13:21:50 +0900 |
commit | 17f2f3054c218485fff598966c39cd3d8a6f6056 (patch) | |
tree | 556f22ef8bc543d2929e5948b85113ffdfe3f3c6 | |
parent | a11ca2ff76d3e1b845282e784c3970b2ebaffd89 (diff) | |
download | rails-17f2f3054c218485fff598966c39cd3d8a6f6056.tar.gz rails-17f2f3054c218485fff598966c39cd3d8a6f6056.tar.bz2 rails-17f2f3054c218485fff598966c39cd3d8a6f6056.zip |
Association loading isn't to be affected by scoping consistently
Follow-up of 5c71000, #29834, and #30271.
Currently, preloading and eager loading are not to be affected by
scoping, with the exception of `unscoped`.
But non eager loaded association access is still affected by scoping.
Although this is a breaking change, the association loading will work
consistently whether preloaded / eager loaded or not.
Before:
```ruby
Post.where("1=0").scoping do
Comment.find(1).post # => nil
Comment.preload(:post).find(1).post # => #<Post id: 1, ...>
Comment.eager_load(:post).find(1).post # => #<Post id: 1, ...>
end
```
After:
```ruby
Post.where("1=0").scoping do
Comment.find(1).post # => #<Post id: 1, ...>
Comment.preload(:post).find(1).post # => #<Post id: 1, ...>
Comment.eager_load(:post).find(1).post # => #<Post id: 1, ...>
end
```
Fixes #34638.
Fixes #35398.
-rw-r--r-- | activerecord/CHANGELOG.md | 27 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/associations/eager_test.rb | 23 | ||||
-rw-r--r-- | activerecord/test/cases/scoping/relation_scoping_test.rb | 4 |
4 files changed, 48 insertions, 8 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index f0396c3d53..08f44e0b91 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,30 @@ +* Association loading isn't to be affected by scoping consistently + whether preloaded / eager loaded or not, with the exception of `unscoped`. + + Before: + + ```ruby + Post.where("1=0").scoping do + Comment.find(1).post # => nil + Comment.preload(:post).find(1).post # => #<Post id: 1, ...> + Comment.eager_load(:post).find(1).post # => #<Post id: 1, ...> + end + ``` + + After: + + ```ruby + Post.where("1=0").scoping do + Comment.find(1).post # => #<Post id: 1, ...> + Comment.preload(:post).find(1).post # => #<Post id: 1, ...> + Comment.eager_load(:post).find(1).post # => #<Post id: 1, ...> + end + ``` + + Fixes #34638, #35398. + + *Ryuta Kamizono* + * Add `rails db:prepare` to migrate or setup a database. Runs `db:migrate` if the database exists or `db:setup` if it doesn't. diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 0bb63b97ae..cf22b850b9 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -225,7 +225,7 @@ module ActiveRecord # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the # through association's scope) def target_scope - AssociationRelation.create(klass, self).merge!(klass.all) + AssociationRelation.create(klass, self).merge!(klass.scope_for_association) end def scope_for_create diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index cd9c8a5285..594d161fa3 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -1400,11 +1400,24 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal expected, FirstPost.unscoped.find(2) end - test "preload ignores the scoping" do - assert_equal( - Comment.find(1).post, - Post.where("1 = 0").scoping { Comment.preload(:post).find(1).post } - ) + test "belongs_to association ignores the scoping" do + post = Comment.find(1).post + + Post.where("1=0").scoping do + assert_equal post, Comment.find(1).post + assert_equal post, Comment.preload(:post).find(1).post + assert_equal post, Comment.eager_load(:post).find(1).post + end + end + + test "has_many association ignores the scoping" do + comments = Post.find(1).comments.to_a + + Comment.where("1=0").scoping do + assert_equal comments, Post.find(1).comments + assert_equal comments, Post.preload(:comments).find(1).comments + assert_equal comments, Post.eager_load(:comments).find(1).comments + end end test "deep preload" do diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index a95ab0f429..8ab0782bbf 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -411,7 +411,7 @@ class HasManyScopingTest < ActiveRecord::TestCase def test_nested_scope_finder Comment.where("1=0").scoping do - assert_equal 0, @welcome.comments.count + assert_equal 2, @welcome.comments.count assert_equal "a comment...", @welcome.comments.what_are_you end @@ -452,7 +452,7 @@ class HasAndBelongsToManyScopingTest < ActiveRecord::TestCase def test_nested_scope_finder Category.where("1=0").scoping do - assert_equal 0, @welcome.categories.count + assert_equal 2, @welcome.categories.count assert_equal "a category...", @welcome.categories.what_are_you end |