Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"TypeError: no implicit conversion of nil into String" when eager loading results

I'm using ruby '2.3.0' and 'rails', '3.2.22.2'.

I need a little help & explanations about a query I've made. Here's my models:

class AssessmentRaw < ActiveRecord::Base
  belongs_to :session
  has_many :schedulers, :class_name => 'MailingScheduler', :as => :owner, :dependent => :destroy
end

class MailingScheduler < ActiveRecord::Base
  belongs_to :owner, :polymorphic => true
end

class Session < ActiveRecord::Base
  has_many :assessment_raws, :dependent => :destroy
end

I want to retrieve all the assessment_raws, and eager load the associated sessions and mailing_schedulers.

1. eager load only sessions

ars = AssessmentRaw.includes(:session).where("sessions.start_at >= ?", 1.year.ago).limit(10)

ars.map { |ar| ar.session.id } => [2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2902, 2903]

`ars.map { |ar| ar.schedulers.try(:size) }`
   MailingScheduler Load (0.6ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 622 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.6ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 725 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.3ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 771 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.3ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 782 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.3ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 881 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.2ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 996 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.3ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 1087 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.3ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 1155 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.2ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 653 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
   MailingScheduler Load (0.2ms)  SELECT "mailing_schedulers".* FROM "mailing_schedulers" WHERE "mailing_schedulers"."owner_id" = 940 AND "mailing_schedulers"."owner_type" = 'AssessmentRaw'
 => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Of course to get the count of the mailing_schedulers, rails must query (N+1 problem)

2. eager load sessions and mailing_schedulers

ars = AssessmentRaw.includes(:schedulers,:session).where("sessions.start_at >= ?", 1.year.ago).limit(10)

TypeError: no implicit conversion of nil into String
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/arel-3.0.3/lib/arel.rb:40:in `initialize'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/arel-3.0.3/lib/arel.rb:40:in `new'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/arel-3.0.3/lib/arel.rb:40:in `sql'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_helper.rb:47:in `block in sanitize'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_helper.rb:45:in `map'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_helper.rb:45:in `sanitize'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_dependency/join_association.rb:104:in `block in join_to'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_dependency/join_association.rb:74:in `each'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_dependency/join_association.rb:74:in `each_with_index'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/associations/join_dependency/join_association.rb:74:in `join_to'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/query_methods.rb:370:in `block in build_joins'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/query_methods.rb:369:in `each'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/query_methods.rb:369:in `build_joins'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/query_methods.rb:266:in `build_arel'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/query_methods.rb:260:in `arel'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/finder_methods.rb:259:in `construct_limited_ids_condition'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/finder_methods.rb:243:in `apply_join_dependency'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/finder_methods.rb:232:in `construct_relation_for_association_find'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation/finder_methods.rb:211:in `find_with_associations'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation.rb:171:in `exec_queries'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation.rb:160:in `block in to_a'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/explain.rb:41:in `logging_query_plan'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation.rb:159:in `to_a'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/activerecord-3.2.22.2/lib/active_record/relation.rb:498:in `inspect'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/railties-3.2.22.2/lib/rails/commands/console.rb:47:in `start'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/railties-3.2.22.2/lib/rails/commands/console.rb:8:in `start'
  from /Users/oim/.rbenv/versions/2.3.0/gemsets/project-gems/gems/railties-3.2.22.2/lib/rails/commands.rb:41:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'irb(main):064:0>

ouch. I think I need a LEFT OUTER JOIN here because all assessment_raws doesn't have mailing_schedulers, right?

Any help appreciated.

like image 308
fro_oo Avatar asked May 01 '16 12:05

fro_oo


1 Answers

This issue occurs due to a change made in Ruby 2.3 where Hash now responds to to_proc which confuses the interpolate method. See this bug report for more details: https://github.com/rails/rails/issues/25010. Also note there is a workaround mentioned which resolved the issue for me, but unless you're sure you don't use the new to_proc it could potentially be dangerous.

What worked for me: I added the suggested monkey patch (as shown below) to the top of my config/application.rb

class Hash
  undef_method :to_proc if self.method_defined?(:to_proc)
end
like image 141
neuronaut Avatar answered Oct 21 '22 20:10

neuronaut