Skip to content
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

ActiveRecord::AssociationTypeMismatch same class but different object_ids #1330

Closed
zminot opened this issue Aug 24, 2019 · 7 comments
Closed
Labels

Comments

@zminot
Copy link

zminot commented Aug 24, 2019

Steps to reproduce

Following up with @hwhelchel on #1029

Isolated the issue here:

When calling FactoryBot.create(:story), the activerecord-6.0.0/lib/active_record/associations/association.rb#raise_on_type_mismatch! method is called. Inside, record.is_a?(reflection.klass) is called which compares the class of record to reflection.klass. When you put a pry statement there, you'll see that both classes are Account, that said, they have different object_ids causing the is_a? equality check to fail and then causing the AssociationTypeMismatch error to be raised. After the error is raised, if you call FactoryBot.reload, and then run FactoryBot.create(:story) again it works.

Reproduction Script

git clone https://github.com/zminot/factory_bot_association_mismatch
bundle install
rails db:create && rails db:migrate
rails c
> FactoryBot.create(:story)
> # ERROR

Expected behavior

> FactoryBot.create(:story)
# => works with no error

Actual behavior

> FactoryBot.create(:story)
# ActiveRecord::AssociationTypeMismatch: Account(#70116037268360) expected, got #<Account id: 1, created_at: "2019-08-24 19:13:54", updated_at: "2019-08-24 19:13:54"> which is an instance of Account(#70116063567540)
from /Users/zachminot/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:279:in `raise_on_type_mismatch!'
> FactoryBot.reload
> FactoryBot.create(:story)
# => works with no error

System configuration

factory_bot version: 5.0.2
rails version: 6.0
ruby version: 2.6.3

@zminot
Copy link
Author

zminot commented Aug 24, 2019

/cc @composerinteralia

@hwhelchel
Copy link

Key lines that cause the error to trigger are:

config.active_job.queue_adapter = :inline in config/environments/development.rb and the has_one_attached :profile_photo in the Account.

Comment either of those out and it runs cleanly.

So maybe when ActiveStorage analyzes the profile photo in the inline job queue a new Account class object is created and some how shares scope with a previously loaded Account class object.

@composerinteralia
Copy link
Collaborator

Eep! I was hoping I had seen the last of that error. It comes up every so often, and we have a workaround in the README.

I appreciate your detailed report and reproduction instructions. This seems like a fun one to dig into. I won't have time right away, so feel free to keep digging if you have any further ideas about why this might be happening.

I was hoping we might get lucky and thoughtbot/factory_bot_rails#343 would fix it, but alas it did not help matters.

I also wondered if the caching of the class in https://github.com/thoughtbot/factory_bot/blob/master/lib/factory_bot/factory.rb#L22-L28 might be causing problems, but I didn't have much luck fiddling with that either.

@hwhelchel
Copy link

@composerinteralia thanks for looking into this. In development if I run:

rails c
> FactoryBot.reload
> FactoryBot.create(:story)

I still get an error.

Screen Shot 2019-08-26 at 10 15 59 PM

Hope that shines some helpful light on the problem.

Turning off spring does fix the issue in development.

When you can revisit, let me know what you find!

@krisleech
Copy link

krisleech commented Apr 6, 2020

Some, but not all, of us are getting the ActiveRecord::AssociationTypeMismatch in seeds.rb when a model is created which references a model created by FactoryBot, e.g.

account = FactoryBot.create(:account)
product = Product.create!(account: account, ....)

I noticed while the class has the same name, it is a different object:

account.class.object_id
=> 69890016840780
Account.object_id
=> 69889857397040

account.class == Account
=> false

ObjectSpace._id2ref(account.class.object_id) == ObjectSpace._id2ref(Account.object_id)
=> false

Doing FactoryBot.reload does not help. Thanks!

Update: disabling spring fixes this, e.g. env env DISABLE_SPRING=1 rake db:seed

@composerinteralia
Copy link
Collaborator

composerinteralia commented Jun 23, 2020

I finally did some deeper digging into this, and it turns out it is not a factory_bot problem after all. Although we had seen ActiveRecord::AssociationTypeMismatch in factory_bot in the past, where calling FactoryBot.reload seemed to fix the problem, this seems to be a separate issue.

To reproduce this problem without factory_bot, I removed the factory_bot_rails gem from the Gemfile of the provided repo, then ran:

story_type = StoryType.new 
account = Account.new
account.profile_photo = Rack::Test::UploadedFile.new(Rails.root.join("spec", "factories", "test-image.jpeg"), "image/jpeg")
account.save!
story_type.account = account
#=> ActiveRecord::AssociationTypeMismatch

Since this is not coming from factory_bot, I am going to close it. I will probably keep poking around in Rails and spring to see if I can figure out what exactly is going on. For some reason the Account class is getting reloaded when running story_type.account = account.

@composerinteralia
Copy link
Collaborator

I dug a bit further into this and it appears to be an interaction between spring, the EventedFileUpdateChecker, and the Active Job inline queue adapter. If you remove any one of these things the problem goes away:

  • Set the DISABLE_SPRING=1 environment variable
  • Remove the line config.active_job.queue_adapter = :inline
  • Remove the line config.file_watcher = ActiveSupport::EventedFileUpdateChecker (which will default to the old non-listen file checker)

I will see if I can get this to the point where I can open an issue on Rails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants