Running tests raises a NameError for sigs receiving or returning an ActiveRecord_AssociationRelation
franciscoj opened this issue · 12 comments
Describe the bug:
When you declare a method which receives or returns an ActiveRecord_AssociationRelation
of some sort, tests fail with:
NameError:
private constant #<Class:0x00007fa75c4e8d28>::ActiveRecord_AssociationRelation referenced
Steps to reproduce:
create a method which returns an association relation on a model
class Post < ApplicationRecord
belongs_to :user
scope :published ->() { where(published: true) }
end
class User < ApplicationRecord
extend T::Sig
has_many :posts
sig { returns(Post::ActiveRecord_AssociationRelation) }
def published_posts
posts.published
end
end
RSpec.describe User do
describe '#published_posts' do
it 'returns only the published posts' do
user = User.create!
published = user.posts.create(published: true)
user.posts.create(published: false)
expect(user.published_posts).to eq([published])
end
end
end
This would raise a NameError
claming that Post::ActiveRecord_AssociationRelation
is a private class.
Note as well that in my case the models are on a rails engine.
Expected behavior:
The test passes
Versions:
- Ruby: 2.4
- Rails: 5.2.3
- Sorbet: Sorbet typechecker 0.4.4891 git 4c9a4534439483b46e869c7212007ad103923203 built on 2019-10-17 22:56:24 GMT debug_symbols=true
- Sorbet-Rails: 0.5.8
You're totally right.
I think I've managed to fix it by moving gem 'sorbet-rails'
on the Gemfile
from the group :development
block to the general group.
Thanks a lot!
I have sorbet-rails in the general group, but I receive the same issue with private constant being referenced.
EDIT: I notice that in development mode, the inherited hook does not fire, while in production mode it does. Guessing it's because of eager_load?
I can confirm that moving it to the general group fixed the issue for me. Besides the code is now running on CI and on production with some MyModel::ActiveRecord_Association
typed methods.
@International what I did to see what was happening on my case was to:
bundle open sorbet-rails
Go to the railties file and add a byebug
on the inherited hook.
Then starting the rails console on development
(where it worked) and on test
, where it didn't. That way I realised what the issue was.
Not sure it can help you debug your case... but you never know!
Guessing it's because of eager_load
I doubt that could be the case, take into account that these patches sorbet-rails
do are hooked to certaing loading events which are fired when things like ActiveRecord::Base
load. It would mean that your app isn't loading those, which would be really weird.
If you wanted to confirm you could add an initializer in the same fashion as sorbet-rails
does and check if it gets called or not.
Hi @franciscoj , thanks for the tip, I did that :)
On one side, what I noticed is that the hook only gets called for about 10 out of 200 models, in development mode, on the other it looks like the railtie should probably be required kind of early so that models coming from gems would also get the hook?
I noticed that also for models defined in gems, the constant is private.
I noticed that also for models defined in gems, the constant is private.
AFAIK for models coming from gems you need to use plugins, like the ones described here https://github.com/chanzuckerberg/sorbet-rails#enabling-built-in-plugins
But I'm afraid I don't know how to add new ones or create your own plugins.
I will try to play around with load order, see if I can force it to get it loaded. Let you know what I find. Thanks
The documentation change is merged