From 2e2021472a651379877bedada58b1627f23f6cdb Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Fri, 4 Oct 2024 13:50:50 +0200 Subject: [PATCH] allow to autosave associations with polymorphic has many through join model and inverse of Before this was not possible: ```ruby class Zine < ActiveRecord::Base has_many :interests, inverse_of: :zine has_many :humans, through: :interests, source: :interestable, source_type: 'Human' end class Interest < ActiveRecord::Base belongs_to :zine, inverse_of: :interests belongs_to :interestable, polymorphic: true, inverse_of: :interests end class Human < ActiveRecord::Base has_many :interests, as: :interestable, inverse_of: :interestable end zine = Zine.create! zine.humans.create! # => ArgumentError: Polymorphic associations do not support computing the class. ``` Now the code checks whether the association is polymorphic and uses the correct code to get the inverse association. --- activerecord/CHANGELOG.md | 4 ++++ .../associations/has_many_through_association.rb | 8 +++++++- .../has_many_through_associations_test.rb | 12 ++++++++++++ activerecord/test/models/zine.rb | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index cc1a505446c06..a5d2e93170d49 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Allow to save records with polymorphic join tables that have inverse of specified. + + *Markus Doits* + * Make Float distinguish between `float4` and `float8` in PostgreSQL. Fixes #52742 diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 50ebb7ca32354..7b8e000842e09 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -93,7 +93,13 @@ def build_record(attributes) @through_scope = scope record = super - inverse = source_reflection.inverse_of + inverse = + if source_reflection.polymorphic? + source_reflection.polymorphic_inverse_of(record.class) + else + source_reflection.inverse_of + end + if inverse if inverse.collection? record.send(inverse.name) << build_through_record(record) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index c83c3b697b671..a1381f182f0fa 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -38,6 +38,9 @@ require "models/session" require "models/sharded" require "models/cpk" +require "models/zine" +require "models/interest" +require "models/human" class HasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags, @@ -1320,6 +1323,15 @@ def test_has_many_through_with_polymorphic_source assert_equal [tags(:general)], post.reload.tags end + def test_has_many_through_with_polymorhic_join_model + zine = Zine.create! + + assert_nothing_raised { zine.polymorphic_humans.build.save! } + + assert_equal 1, zine.polymorphic_humans.count + assert_equal 1, zine.interests.count + end + def test_has_many_through_obeys_order_on_through_association owner = owners(:blackbeard) assert_includes owner.toys.to_sql, "pets.name desc" diff --git a/activerecord/test/models/zine.rb b/activerecord/test/models/zine.rb index 6f361665efc7a..5d4e226267e96 100644 --- a/activerecord/test/models/zine.rb +++ b/activerecord/test/models/zine.rb @@ -2,4 +2,5 @@ class Zine < ActiveRecord::Base has_many :interests, inverse_of: :zine + has_many :polymorphic_humans, through: :interests, source_type: "Human" end