Skip to content

Commit e11ebc0

Browse files
authored
Merge pull request rails#47889 from aharpole/fix-foreign-key-infinite-recursion
fix infinite recursion with foreign_key
2 parents 32819c5 + 4a4cc21 commit e11ebc0

File tree

4 files changed

+10
-5
lines changed

4 files changed

+10
-5
lines changed

activerecord/lib/active_record/reflection.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -493,12 +493,12 @@ def join_table
493493
@join_table ||= -(options[:join_table]&.to_s || derive_join_table)
494494
end
495495

496-
def foreign_key
496+
def foreign_key(infer_from_inverse_of: true)
497497
@foreign_key ||= if options[:query_constraints]
498498
# composite foreign keys support
499499
options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
500500
else
501-
-(options[:foreign_key]&.to_s || derive_foreign_key)
501+
-(options[:foreign_key]&.to_s || derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of))
502502
end
503503
end
504504

@@ -726,13 +726,13 @@ def derive_class_name
726726
class_name.camelize
727727
end
728728

729-
def derive_foreign_key
729+
def derive_foreign_key(infer_from_inverse_of: true)
730730
if belongs_to?
731731
"#{name}_id"
732732
elsif options[:as]
733733
"#{options[:as]}_id"
734-
elsif options[:inverse_of]
735-
inverse_of.foreign_key
734+
elsif options[:inverse_of] && infer_from_inverse_of
735+
inverse_of.foreign_key(infer_from_inverse_of: false)
736736
else
737737
active_record.model_name.to_s.foreign_key
738738
end

activerecord/test/cases/reflection_test.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "cases/helper"
44
require "models/topic"
55
require "models/customer"
6+
require "models/comment"
67
require "models/company"
78
require "models/company_in_module"
89
require "models/ship"
@@ -461,6 +462,7 @@ def test_never_validate_association_if_explicit
461462
def test_foreign_key
462463
assert_equal "author_id", Author.reflect_on_association(:posts).foreign_key.to_s
463464
assert_equal "category_id", Post.reflect_on_association(:categorizations).foreign_key.to_s
465+
assert_equal "comment_id", FirstPost.reflect_on_association(:comment_with_inverse).foreign_key.to_s
464466
end
465467

466468
def test_foreign_key_is_inferred_from_model_name

activerecord/test/models/comment.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Comment < ActiveRecord::Base
2323
belongs_to :first_post, foreign_key: :post_id
2424
belongs_to :special_post_with_default_scope, foreign_key: :post_id
2525

26+
has_one :post_with_inverse, ->(comment) { where(id: comment.post_id) }, class_name: "FirstPost", inverse_of: :comment_with_inverse
27+
2628
has_many :children, class_name: "Comment", inverse_of: :parent
2729
belongs_to :parent, class_name: "Comment", counter_cache: :children_count, inverse_of: :children
2830

activerecord/test/models/post.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class FirstPost < ActiveRecord::Base
234234

235235
has_many :comments, foreign_key: :post_id
236236
has_one :comment, foreign_key: :post_id
237+
has_one :comment_with_inverse, class_name: "Comment", inverse_of: :post_with_inverse
237238
end
238239

239240
class PostWithDefaultSelect < ActiveRecord::Base

0 commit comments

Comments
 (0)