diff --git a/lib/tapioca/dsl/compilers/active_record_associations.rb b/lib/tapioca/dsl/compilers/active_record_associations.rb index da54fdc4b..ce2f56259 100644 --- a/lib/tapioca/dsl/compilers/active_record_associations.rb +++ b/lib/tapioca/dsl/compilers/active_record_associations.rb @@ -108,6 +108,9 @@ class ActiveRecordAssociations < Compiler class SourceReflectionError < StandardError end + class SelfReferentialSourceReflectionError < StandardError + end + class MissingConstantError < StandardError #: String attr_reader :class_name @@ -167,6 +170,10 @@ def populate_associations(mod) add_error(<<~MSG.strip) Cannot generate association `#{reflection.name}` on `#{constant}` since the source of the through association is missing. MSG + rescue SelfReferentialSourceReflectionError + add_error(<<~MSG.strip) + Cannot generate association `#{reflection.name}` on `#{constant}` since the source of the through association is itself. Specify the `source:` option. + MSG rescue MissingConstantError => error add_error(<<~MSG.strip) Cannot generate association `#{declaration(reflection)}` on `#{constant}` since the constant `#{error.class_name}` does not exist. @@ -279,6 +286,8 @@ def validate_reflection!(reflection) # and fails with a cryptic error, otherwise. if reflection.through_reflection? raise SourceReflectionError unless reflection.source_reflection + # A source reflection pointing back to itself makes `.klass` recurse forever + raise SelfReferentialSourceReflectionError if reflection.source_reflection.equal?(reflection) end # For non-polymorphic reflections, `.klass` should not be raising diff --git a/spec/tapioca/dsl/compilers/active_record_associations_spec.rb b/spec/tapioca/dsl/compilers/active_record_associations_spec.rb index 5999f9439..c8b1e286b 100644 --- a/spec/tapioca/dsl/compilers/active_record_associations_spec.rb +++ b/spec/tapioca/dsl/compilers/active_record_associations_spec.rb @@ -816,6 +816,22 @@ def shop_previously_changed?; end Cannot generate association `manager` on `Post` since the source of the through association is missing. MSG end + + it "generates RBI file for has_many :through association whose source is itself" do + add_ruby_file("group.rb", <<~RUBY) + class Group < ActiveRecord::Base + has_many :sub_groups, class_name: "Group", foreign_key: "parent_id" + has_many :child_group_members, through: :sub_groups + end + RUBY + + refute_includes(rbi_for(:Group), "child_group_members") + + assert_equal(1, generated_errors.size) + assert_equal(<<~MSG.strip, generated_errors.first) + Cannot generate association `child_group_members` on `Group` since the source of the through association is itself. Specify the `source:` option. + MSG + end end end