Skip to content

Commit bd93237

Browse files
committed
Support assignments for composite key has_many through associations
Given a has_many through association with a composite foreign key, like: ```ruby class BlogPost < ApplicationRecord query_constraints :blog_id, :id has_many :blog_post_tags, query_constraints: [:blog_id, :blog_post_id] has_many :tags, through: :blog_post_tags end class BlogPostTag < ApplicationRecord belongs_to :blog_post, query_constraints: [:blog_id, :blog_post_id] belongs_to :tag, query_constraints: [:blog_id, :tag_id] end class Tag < ApplicationRecord query_constraints :blog_id, :id has_many :blog_post_tags, query_constraints: [:blog_id, :tag_id] has_many :blog_posts, through: :blog_post_tags end ``` It should be possible to assign tags to a blog post: ```ruby blog_post = BlogPost.create!(title: "Hello world") blog_post.tags << Tag.new(name: "ruby") ```
1 parent b0dd7c7 commit bd93237

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

activerecord/lib/active_record/associations/has_many_through_association.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ def build_through_record(record)
6969

7070
def through_scope_attributes
7171
scope = through_scope || self.scope
72-
scope.where_values_hash(through_association.reflection.name.to_s).
73-
except!(through_association.reflection.foreign_key,
74-
through_association.reflection.klass.inheritance_column)
72+
attributes = scope.where_values_hash(through_association.reflection.name.to_s)
73+
except_keys = [
74+
*Array(through_association.reflection.foreign_key),
75+
through_association.reflection.klass.inheritance_column
76+
]
77+
attributes.except!(*except_keys)
7578
end
7679

7780
def save_through_record(record)

activerecord/test/cases/associations_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,27 @@ def test_assign_composite_foreign_key_belongs_to_association_with_autosave
231231
assert_equal(another_blog.id, comment.blog_id)
232232
assert_equal(comment.blog_post_id, blog_post.id)
233233
end
234+
235+
def test_append_composite_has_many_through_association
236+
blog_post = sharded_blog_posts(:great_post_blog_one)
237+
tag = Sharded::Tag.new(name: "Ruby on Rails", blog_id: blog_post.blog_id)
238+
tag.save
239+
240+
blog_post.tags << tag
241+
242+
assert_includes(blog_post.reload.tags, tag)
243+
assert_predicate Sharded::BlogPostTag.where(blog_post_id: blog_post.id, blog_id: blog_post.blog_id, tag_id: tag.id), :exists?
244+
end
245+
246+
def test_append_composite_has_many_through_association_with_autosave
247+
blog_post = sharded_blog_posts(:great_post_blog_one)
248+
tag = Sharded::Tag.new(name: "Ruby on Rails", blog_id: blog_post.blog_id)
249+
250+
blog_post.tags << tag
251+
252+
assert_includes(blog_post.reload.tags, tag)
253+
assert_predicate Sharded::BlogPostTag.where(blog_post_id: blog_post.id, blog_id: blog_post.blog_id, tag_id: tag.id), :exists?
254+
end
234255
end
235256

236257
class AssociationProxyTest < ActiveRecord::TestCase

0 commit comments

Comments
 (0)