diff options
author | yui-knk <spiketeika@gmail.com> | 2016-02-02 20:57:55 +0900 |
---|---|---|
committer | yui-knk <spiketeika@gmail.com> | 2017-08-22 18:51:43 +0900 |
commit | 30ef715d40cd49d017524824bfbb92e4bd4ab6a4 (patch) | |
tree | 56963d44c52c5624b35b936b0aff1421a9d7157d /activerecord | |
parent | 1fe41329c6ffcbb52c9762d28d780e838584e63d (diff) | |
download | rails-30ef715d40cd49d017524824bfbb92e4bd4ab6a4.tar.gz rails-30ef715d40cd49d017524824bfbb92e4bd4ab6a4.tar.bz2 rails-30ef715d40cd49d017524824bfbb92e4bd4ab6a4.zip |
Automatically guess the inverse associations for STI
ActiveRecord associations automatically guess the inverse associations.
But this feature does not work correctly on assoctions for STI.
For example, before this commit
```
class Post < ActiveRecord::Base
belongs_to :author
end
class SpecialPost < Post; end
class Author < ActiveRecord::Base
has_many :posts
has_many :special_posts
end
```
`author.posts.first.author` works correctly, but
`author.special_posts.first.author` does not work correctly.
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/CHANGELOG.md | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/associations/inverse_associations_test.rb | 39 |
3 files changed, 43 insertions, 2 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b39d28ca31..4a840a57b5 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Automatically guess the inverse associations for STI. + + *Yuichiro Kaneko* + * Ensure `sum` honors `distinct` on `has_many :through` associations Fixes #16791. diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index b847933b2e..e35049bb41 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -657,7 +657,7 @@ module ActiveRecord # from calling +klass+, +reflection+ will already be set to false. def valid_inverse_reflection?(reflection) reflection && - klass.name == reflection.active_record.name && + klass <= reflection.active_record && can_find_inverse_of_automatically?(reflection) end diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 536077fb92..86a034b429 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -18,6 +18,8 @@ require "models/admin/user" require "models/developer" require "models/company" require "models/project" +require "models/author" +require "models/post" class AutomaticInverseFindingTests < ActiveRecord::TestCase fixtures :ratings, :comments, :cars @@ -60,6 +62,20 @@ class AutomaticInverseFindingTests < ActiveRecord::TestCase assert_equal rating_reflection, comment_reflection.inverse_of, "The Comment reflection's inverse should be the Rating reflection" end + def test_has_many_and_belongs_to_should_find_inverse_automatically_for_sti + author_reflection = Author.reflect_on_association(:posts) + author_child_reflection = Author.reflect_on_association(:special_posts) + post_reflection = Post.reflect_on_association(:author) + + assert_respond_to author_reflection, :has_inverse? + assert author_reflection.has_inverse?, "The Author reflection should have an inverse" + assert_equal post_reflection, author_reflection.inverse_of, "The Author reflection's inverse should be the Post reflection" + + assert_respond_to author_child_reflection, :has_inverse? + assert author_child_reflection.has_inverse?, "The Author reflection should have an inverse" + assert_equal post_reflection, author_child_reflection.inverse_of, "The Author reflection's inverse should be the Post reflection" + end + def test_has_one_and_belongs_to_automatic_inverse_shares_objects car = Car.first bulb = Bulb.create!(car: car) @@ -267,7 +283,7 @@ class InverseHasOneTests < ActiveRecord::TestCase end class InverseHasManyTests < ActiveRecord::TestCase - fixtures :men, :interests + fixtures :men, :interests, :posts, :authors def test_parent_instance_should_be_shared_with_every_child_on_find m = men(:gordon) @@ -281,6 +297,27 @@ class InverseHasManyTests < ActiveRecord::TestCase end end + def test_parent_instance_should_be_shared_with_every_child_on_find_for_sti + a = authors(:david) + ps = a.posts + ps.each do |p| + assert_equal a.name, p.author.name, "Name of man should be the same before changes to parent instance" + a.name = "Bongo" + assert_equal a.name, p.author.name, "Name of man should be the same after changes to parent instance" + p.author.name = "Mungo" + assert_equal a.name, p.author.name, "Name of man should be the same after changes to child-owned instance" + end + + sps = a.special_posts + sps.each do |sp| + assert_equal a.name, sp.author.name, "Name of man should be the same before changes to parent instance" + a.name = "Bongo" + assert_equal a.name, sp.author.name, "Name of man should be the same after changes to parent instance" + sp.author.name = "Mungo" + assert_equal a.name, sp.author.name, "Name of man should be the same after changes to child-owned instance" + end + end + def test_parent_instance_should_be_shared_with_eager_loaded_children m = Man.all.merge!(where: { name: "Gordon" }, includes: :interests).first is = m.interests |