Shopify / tapioca

The swiss army knife of RBI generation
MIT License
728 stars 121 forks source link

Fix missing array signature for ActiveRecordRelation #create #1946

Closed bitwise-aiden closed 2 months ago

bitwise-aiden commented 3 months ago

Motivation

If passed an array, ActiveRecord's #create method will return an array of that models type. This is missing in the current implementation.

Implementation

I've split the create methods so that the ones that are able to take arrays can now do so and return the type too.

Question for reviewers

Is there a preference on how to define constants for the single vs multi?

Tests

iMacTia commented 1 month ago

I read the comments around the signature order, but I don't think this is still working as expected.

After upgrading to tapioca 0.16 in our codebase, we started having issues where we call find_or_create passing T.untyped. This is because sorbet now thinks that in that scenario we get an array back, even though we're passing a single T.untyped value and therefore we're only getting back a single record.

The only solution I found was to properly type the parameter so that it wouldn't be T.untyped. Ideally, Sorbet would distinguish between T.untyped and T::Array[T.untyped], but as the comment specifies, T.untyped matches T::Array[T.untyped].

I'm not sure this is gonna be easy to fix, as this may be due to a limitation in Sorbet, but maybe we could leverage T.anything instead? Or some other clever hack to make this work better?