rails icon indicating copy to clipboard operation
rails copied to clipboard

ActiveRecord: Fix preloading when using a double as foreign_key

Open sdrioux opened this issue 4 years ago • 5 comments

Summary

I have a table called accounts in my Postgres database. One of its columns acts as a foreign key for another table in my database called businesses, however, the foreign key is a double, while the primary key is an integer. When trying to preload businesses for accounts, I get the error below.

The issue is that when assigning preloaded associations for a given record, the foreign key gets converted to a string from a float, ie "6.0", while the primary key integer gets converted as "6". As a result, it can't find an owner for the association.

To fix this, I would like to check for the existence of the key as a float, and convert it to an integer first.

It looks like this has been a long-standing issue, and was actually reported back in 2012: https://github.com/rails/rails/pull/6637, but the PR was abandoned.

undefined method `first' for nil:NilClass

/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/associations/preloader/association.rb:121:in `block in records_for'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/core.rb:546:in `init_with_attributes'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/persistence.rb:403:in `instantiate_instance_of'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/querying.rb:66:in `block (2 levels) in find_by_sql'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/result.rb:62:in `block in each'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/result.rb:62:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/result.rb:62:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/querying.rb:66:in `map'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/querying.rb:66:in `block in find_by_sql'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/querying.rb:61:in `find_by_sql'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation.rb:843:in `block in exec_queries'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation.rb:861:in `skip_query_cache_if_necessary'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation.rb:828:in `exec_queries'
/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation.rb:631:in `load'

Other Information

I'd like to create a test for this, but I'm not entirely sure how to go about doing that. If anyone has any guidance I would appreciate it.

Thank you!

sdrioux avatar Oct 29 '21 00:10 sdrioux

Looks like this would also fix this issue: https://github.com/rails/rails/issues/19891

sdrioux avatar Oct 29 '21 14:10 sdrioux

Oh. My. God. Finally!

noma4i avatar Nov 02 '21 12:11 noma4i

what-huh

sdrioux avatar Dec 16 '21 21:12 sdrioux

I feel similarly over on https://github.com/rails/rails/pull/43402, which also happens to fix something with preloading. I hope you can get eyes on yours soon!

mattalat avatar Mar 11 '22 20:03 mattalat

Could you please add tests and a changelog entry?

willianveiga avatar Jun 28 '24 19:06 willianveiga