tapioca icon indicating copy to clipboard operation
tapioca copied to clipboard

SystemStackError for has_many assocation that points to own model

Open jackwurth opened this issue 1 year ago • 4 comments

I have a setup involving a model with a has_many that points to itself

class Group < ApplicationRecord
    has_many :sub_groups, class_name: "Group", primary_key: "id", foreign_key: "parent_id"
end

each record has a parent_id to point to it's parent group.

This setup works fine with rails, but tapioca crashes when it tries to generate it with a SystemStackError

activerecord-7.1.3.2/lib/active_record/reflection.rb:967:in 'through_reflection': stack level too deep (SystemStackError)`
...
/thor-1.3.1/lib/thor/base.rb:584:in start
/tapioca-0.13.3/exe/tapioca:25:in '<top (required)>

Tested with Tapioca version 0.13.3

jackwurth avatar Apr 25 '24 22:04 jackwurth

I wasn't able to reproduce. If you can share a small app that has the same problem I can take a look.

KaanOzkan avatar Apr 30 '24 18:04 KaanOzkan

Ah my bad it turns out that there's more to it than what I thought, the traceback doesn't really point to the source of the error.

I've uploaded a demo here: https://github.com/jackwurth/sorbet_bug_demo Also attached as zip: sorbet_test.zip

The test setup is: Group A Group B with parent set to "Group A" Member A with group set to "Group B"

Running bundle exec tapioca dsl triggers the crash. Rails can handle this weird setup just fine.

it seems the cause is more likely to be to do with the has_many that calls a method. https://github.com/jackwurth/sorbet_bug_demo/blob/main/app/models/group.rb#L11

jackwurth avatar Apr 30 '24 21:04 jackwurth

We are triggering the recursive calls here which eventually attempts to call Reflection.class_name.

There might be a better way to do this but I think we can filter out this case by checking if reflection.source_reflection_name matches reflection.delegate_reflection.name.

KaanOzkan avatar May 01 '24 15:05 KaanOzkan

@paracycle do you have context on the internals? We enter infinite recursion while validating a has_many through association that points to the same model https://github.com/jackwurth/sorbet_bug_demo/blob/main/app/models/group.rb#L8.

I was thinking if we can reliably detect this by looking at the reflection name (above comment) we could skip validating and return T.untyped?

KaanOzkan avatar May 01 '24 15:05 KaanOzkan