2016-04-08 19 views
0

Ich habe eine Rails-App, wo ich oft xls-Dateien mit mehreren Werten generieren muss. Dazu ich Kunden Aufträge in meinem Controller laden (valid ist nur ein benutzerdefinierter Bereich)Rails - Zählschleife mit Active Record

@orders = Order.valid.order('id DESC') 

Meiner Ansicht nach, ich mag mit verschiedenen Bereichen für die einzelnen Aufträge Mahlzeiten zählen (i entfernt alle XML-Tags, die sind nicht interessant hier):

<% @orders.each do |order| %> 
    <%= order.meals.count %> 
    <%= order.meals.meat.count %> 
    <%= order.meals.fish.count %> 
    <%= order.meals.drink.count %> 
    <%= order.meals.dessert.count %> 
<% end %> 

Mein Problem ist, dass dies eine sehr große Anzahl von SQL-Anfragen generiert.

Ich habe versucht, Mahlzeiten wie diese vorab zu laden:

@orders = Order.valid.order('id DESC').preload(:meals) 

Aber Anfragen

auch ein altes Juwel erzeugt werden, halten zählen

ich gefunden: preload_count, dies zu tun, aber es mit Schienen nicht funktioniert nicht 4 .

Gibt es eine Möglichkeit, meine Anfragen zu optimieren?

EDIT

Nach vielen Versuchen und Hilfe von Andrey Dejneko, meine Anfrage in diese gedreht:

Order.includes(:meals).valid.order('id DESC').references(:meals) 

Dann ist es mir klar, kann aus Mahlzeit Arten kommen, die in meinem DB in einer anderen Tabelle sind

Order.eager_load(meals: :type).valid.order('orders.id DESC').references(:meals) 

Aber immer noch, hier sind meine db Anfragen:

(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 [["order_id", 1044]] 
    (0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 [["order_id", 1044]] 
    (0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "meat"]] 
    (0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "meat"]] 
    (0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "fish"]] 
    (0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "fish"]] 
    (0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "drink"]] 
    (0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "drink"]] 
    (0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "dessert"]] 
+1

Beim Iterieren von Sammlungen sollten Sie 'find_each' verwenden, das in Stapelform statt" each "eingefügt wird, um zu verhindern, dass eine potenziell massive Ergebnismenge in den Speicher geladen wird. –

+0

Danke, ich habe das in meinem Code geändert, aber es beantwortet meine Frage nicht:/ – Shrolox

Antwort

1

gehen mit

@orders = Order.includes(:meals).valid.order('id DESC') 

wenn Sie Aufträge mit Mahlzeiten (keine Aufträge, wo Essen nil ist) haben wollen, gehen mit:

@orders = Order.joins(:meals).valid.order('id DESC') 

ein gelesen haben über AR querying.

+0

Versucht dies, aber AR generiert immer noch eine Anfrage, um die Anzahl zu erhalten. es ist eager_loading zählt, dass ich will. Oder vielleicht habe ich dich falsch verstanden – Shrolox

+0

Macht durch mein Missverständnis. Könnten Sie versuchen 'Order.includes (: Mahlzeiten) .valid.order ('ID DESC'). Referenzen (: Mahlzeiten)'? –

+0

Danke. Ich habe das versucht, aber die Anzahl der Anfragen läuft noch. Da Essensbereiche sich auf eine andere Datenbank (Typen) beziehen, habe ich versucht, diese mit einer eifrigen Ladung einzubeziehen. Ich werde meinen Beitrag aktualisieren, um es Ihnen zu zeigen. – Shrolox

0

Wenn Ihre Modelle eine Beziehung has_many gehört_to haben, können Sie die Verknüpfungen mit eager laden. This ist ein guter Artikel über eifriges Laden.

+0

Danke. Ich habe equired_loading versucht, aber es ist mir nicht möglich, die Anzahl in nur einer Anfrage vorzuladen. – Shrolox

Verwandte Themen