Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord :includes - how to use map with loaded associations?

I have a small rails app, and I'm trying to get some order statistics. So I have an Admin model, and an Order model, with one-to-many association.

class Admin < ActiveRecord::Base
  attr_accessible :name
  has_many :orders
class Order < ActiveRecord::Base
  attr_accessible :operation
  belongs_to :admin

And I'm trying to get specifical orders using this query:

admins = Admin.where(...).includes(:orders).where('orders.operation = ?', 'new gifts!')

That works just as expected. But when I try to make json using map like that

admins.map {|a| [a.name, a.orders.pluck(:operation)]}

Rails loads orders again using new query, ignoring already loaded objects.

(5.6ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 26
(6.8ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 24
(2.9ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 30
(3.3ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 29
(4.8ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 27
(3.3ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 28
(5.1ms)  SELECT "orders"."operation" FROM "orders" WHERE "orders"."admin_id" = 25

When I try to use loop instead of map, it works as it should:

admins.each do |a|
  p a.orders.pluck(:operation)
end

this code doesn't load all orders, and prints only those loaded in the first query. Is it possible to get the same result using map? What are the drawbacks of using loop instead of map?

like image 988
Timur Minulin Avatar asked Mar 23 '23 05:03

Timur Minulin


1 Answers

pluck should always make a new query to database. Not sure why you think it does not happen in an each loop. Maybe you did not see the log because it is in between your prints?

There are 2 possibilities how to avoid additional queries.

  1. Since orders are already loaded because you include them, you can do admins.map {|a| [a.name, a.orders.collect(&:operation)]}

  2. Using joins (see @tihom's comment).

Edit: I just tested the each/ map behavior and it reloads every time as expected.

like image 96
mechanicalfish Avatar answered Apr 06 '23 10:04

mechanicalfish