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

Merge pull request #16314 from zoltankiss/allow-nested-has-many-associations-on-unpersisted-parent-instances

fix nested `has many :through` associations on unpersisted parent instances
This commit is contained in:
Ryuta Kamizono 2018-01-10 20:25:37 +09:00
commit 027f865fc8
4 changed files with 76 additions and 1 deletions

View file

@ -1,3 +1,41 @@
* Fix nested `has_many :through` associations on unpersisted parent instances.
For example, if you have
class Post < ActiveRecord::Base
belongs_to :author
has_many :books, through: :author
has_many :subscriptions, through: :books
end
class Author < ActiveRecord::Base
has_one :post
has_many :books
has_many :subscriptions, through: :books
end
class Book < ActiveRecord::Base
belongs_to :author
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :book
end
Before:
If `post` is not persisted, then `post.subscriptions` will be empty.
After:
If `post` is not persisted, then `post.subscriptions` can be set and used
just like it would if `post` were persisted.
Fixes #16313.
*Zoltan Kiss*
* Fixed inconsistency with `first(n)` when used with `limit()`.
The `first(n)` finder now respects the `limit()`, making it consistent
with `relation.to_a.first(n)`, and also with the behavior of `last(n)`.

View file

@ -68,7 +68,7 @@ module ActiveRecord
end
def foreign_key_present?
through_reflection.belongs_to? && !owner[through_reflection.foreign_key].nil?
through_reflection.belongs_to_or_through? && !owner[through_reflection.foreign_key].nil?
end
def ensure_mutable

View file

@ -504,6 +504,10 @@ module ActiveRecord
@association_scope_cache.clear
end
def belongs_to_or_through?
belongs_to?
end
def nested?
false
end
@ -836,6 +840,10 @@ module ActiveRecord
source_reflection.join_scopes(table, predicate_builder) + super
end
def belongs_to_or_through?
through_reflection.belongs_to_or_through?
end
def has_scope?
scope || options[:source_type] ||
source_reflection.has_scope? ||

View file

@ -1308,6 +1308,35 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
end
def test_single_has_many_through_association_with_unpersisted_parent_instance
post_with_single_has_many_through = Class.new(Post) do
def self.name; "PostWithSingleHasManyThrough"; end
has_many :subscriptions, through: :author
end
post = post_with_single_has_many_through.new
post.author = Author.create!(name: "Federico Morissette")
book = Book.create!(name: "essays on single has many through associations")
post.author.books << book
subscription = Subscription.first
book.subscriptions << subscription
assert_equal [subscription], post.subscriptions.to_a
end
def test_nested_has_many_through_association_with_unpersisted_parent_instance
post_with_nested_has_many_through = Class.new(Post) do
def self.name; "PostWithNestedHasManyThrough"; end
has_many :books, through: :author
has_many :subscriptions, through: :books
end
post = post_with_nested_has_many_through.new
post.author = Author.create!(name: "Obie Weissnat")
book = Book.create!(name: "essays on nested has many through associations")
post.author.books << book
subscription = Subscription.first
book.subscriptions << subscription
assert_equal [subscription], post.subscriptions.to_a
end
private
def make_model(name)
Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }