-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type the rails find method #1145
Conversation
For find_by, we have no problem inferring that it will return T.nilable(constant_name), however we eject from trying to type find. Per https://github.com/rails/rails/blob/33100212244efbd1adf21587e1e37090fdd3591d/activerecord/lib/active_record/relation/finder_methods.rb#L13-L19 (current main revision at time of authoriship) We should be able to provide something a bit better, even if developers have to T.cast when they know they're not getting an array back. I have _zero_ idea if there was a specific reason for T.untyped in this regard, but I thought I'd contribute this as a suggestion if this is tenable, or a question if it is not so I can better understand.
Thanks Rafael! |
Thank you for the pull request. I wonder if we have a better way to document this decision. Maybe we should document in the manual for this generator and expose the manual in the generated rbi? |
I did read the manual, and I did do a quick search before asking and looking (sorry I didn't find it haha). Could also be an inline comment on the generator itself where the method is defined. I think because it's so odd, including it in the RBI isn't such a bad idea! But I don't know if that's a current practice. |
This info isn't in the manual though, so maybe we should start adding it there? |
Just to avoid necro-ing the other thread really quick. I did expect this to introduce a type error when using Model.find(1). The PR you linked noted that this was not ideal (I agree, re the future overloaded types stuff), but I was prepared to have to do the following: Original sorbet run What I would expect to have to do: sorbet run I know that this isn't ideal, but we have to do exactly this for ActionController::Parameters, as it can return three different types. Is the decision here that this extra friction isn't worth having the value typed? I guess in this case we can still cast T.untyped to Model to get our typing? Maybe that's the message to be put in the manual if we don't want to force the cast? E.g. (reductively paraphrasing here) "If you need a strong type from #find, you can cast from untyped like so.." user = T.cast(User.find(1), User) It's not a big deal, but mostly it's the method lookup from the LSP that matters the most in this case. |
I think But you are right that cast is the answer here, and even with |
Yep! Cool, if you like I can write up a thing for the manual. |
Please go ahead |
Motivation
For find_by, we have no problem inferring that it will return
T.nilable(constant_name), however we eject from trying to type find. Per
https://github.com/rails/rails/blob/33100212244efbd1adf21587e1e37090fdd3591d/activerecord/lib/active_record/relation/finder_methods.rb#L13-L19
(current main revision at time of authoriship)
We should be able to provide something a bit better, even if developers
have to T.cast when they know they're not getting an array back.
I have zero idea if there was a specific reason for T.untyped in this
regard, but I thought I'd contribute this as a suggestion if this is
tenable, or a question if it is not so I can better understand.
Motivation
Implementation
Instead of having ActiveRecord::Base::find return T.untyped, have it return the constant it belongs to similar to find_by, or an array of those constants per the documentation and code on rails/rails
Tests
I added the test I thought relevant, the tests take a while so I'll check branch CI for anything else I've missed.