How to set preload scope for Rails Associations::Preloader?
Asked Answered
M

1

9

I need to preload associations of the model with complex conditions. NO, includes doesn't work for me. It generate wrong SQL for my task.

I take a look to the ActiveRecord::Associations::Preloader and find that he take an preload_scope argument:

http://apidock.com/rails/v4.2.1/ActiveRecord/Associations/Preloader/preload

 def preload(records, associations, preload_scope = nil)
  # ...
 end

But I can't find any example using it. What is preload_scope in this case? And how I can use it for filtering associations? Thanks!

Mountaintop answered 17/4, 2015 at 9:24 Comment(0)
T
4

ActiveRecord doesn't expose this through #preloads on relation: https://github.com/rails/rails/blob/0aefa97689d001ca9a98db76bbad1bbbb0e51c9c/activerecord/lib/active_record/relation.rb#L663 – as you can see only records and associations parameters are passed.

You can reach into ActiveRecord internals and call Preloader directly:

rows = Projects.all.to_a
ActiveRecord::Associations::Preloader.new.preload(rows, :current_task, Struct.new(:values, :bind_values).new({where: "active"}, []))
Tull answered 30/4, 2015 at 8:46 Comment(4)
Oh, thanks, it works! But why it creates so many queries? User Load (12.1ms) SELECT "users".* FROM "users" WHERE (created_at > '2015-01-01') AND "users"."cat" IN (52, 50, 51, 53) User Load (1.2ms) SELECT "users".* FROM "users" WHERE (created_at > '2015-01-01') User Load (5.1ms) SELECT "users".* FROM "users"Mountaintop
users = Car.find(1).users rows = users.to_a ActiveRecord::Associations::Preloader.new.preload(rows, :activities, Struct.new(:values, :bind_values).new({where: "created_at > '2015-01-01'"}, []))Mountaintop
The excessive number of queries was also highlighted here (but not investigated by Rails team since they consider Preloader private stuff)Nason
How could you use the preload_scope to return a limit? For example return only 5 elements?Diaphanous

© 2022 - 2024 — McMap. All rights reserved.