tapioca: Missing `ActiveRecord#save` signature
I was expecting to find save and save! in the methods generated by https://github.com/Shopify/tapioca/blob/main/lib/tapioca/dsl/compilers/active_record_relations.rb, together with build, create and all the others, but for some reason it’s missing.
Is it somewhere else, or was it simply missed? And if it’s missing, would you be open to a PR to add it there?
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 17 (9 by maintainers)
@iMacTia I’m mostly rephrasing @paracycle’s response but it may be of help.
dslcommand’s job is to expose metaprogramming to Sorbet. Relations compiler’s documentation can paint a more detailed picture. It exposes methods toActiveRecord::Baseby representing the underlying relationships to Sorbet using synthetic entities. Methods such asbuildaren’t available to Sorbet without this compiler due to metaprogramming. They exist inActiveRecord::Relationwhich isn’t statically mixed intoActiveRecord::Base.On the other hand
saveandsave!are methods available to Sorbet after a “simpler” gem RBI generation since Sorbet knows thatActiveRecord::BaseincludesActiveRecord::Persistence. All tapioca is doing is loading the gems and writing the constant definitions, method definitions and the mixin information to a file (docs). You can check the RBI generated foractiverecordand findYou can also find the definitions for
saveandsave!in the same file under theActiveRecord::Persistencemodule. This means we already have gem RBIs generated for these methods unlikebuild/create.Now if you write a DSL generator to improve the signature of
savefor each Model in your application it would conflict with the method definitions in gem RBIs since there will be 2 definitions for the same method. It’s also against the spirit since the methods aren’t defined by metaprogramming, which was whydslcommand was introduced.save/save!are statically available toActiveRecord::Baseand don’t need any extra processing unlikebuild/create.Also one thing to note is that if you went the DSL compiler route it doesn’t have to live inside tapioca. You can write your custom compiler and tapioca will execute it during
dslcommand.Hope this clears things up a bit.
Yes that’s correct. My bad earlier, I forgot about that one. I can’t think of an edge case that invalidates
T.self_typeso it’s a good replacement to returning record itself given the usage is sensible. Keep in mind though in some more complex cases receiver could beT.untypedand therefore return type would also beT.untyped.