2016-09-29 4 views
1

Ich weiß, das muss einfach sein, aber ich bin wirklich verloren.Schienen 4 - Summenwerte nach externem Schlüssel gruppiert

Drei Modelle: Job, Aufgabe und Funktion, wie folgt:

Job 
has_many :tasks 

Task 
belongs_to :job 
belongs_to :operation 

Operation 
has_many :jobs 

Job hat ein Attribut, total_pieces, die mir sagt, wie viele Stücke, die Sie benötigen. Für jede Job können Sie eine Nummer Tasks hinzufügen, die zu verschiedenen Operations (Schneiden, Bohren, etc.) gehören kann und für jede Aufgabe können Sie eine Anzahl von Stücken einrichten. Ich weiß nicht im Voraus, wie viele Operations wird für eine einzige Job benötigt, aber ich muss Benutzer über die Anzahl der Stücke für diese Operation verlassen, wenn eine neue Task eingefügt wird.

Nehmen wir ein Beispiel machen:

Job 1: total_pieces=100 
- Task 1: operation 1(cutting), pieces=20 
- Task 2: operation 1(cutting), pieces=30 
- Task 3: operation 2(drilling), pieces=20 

Ich brauche den Benutzer zu alarmieren, die sie benötigen noch 50 Stücke schneiden und 80. Hypothetisch zu bohren, wenn ich hinzufügen:

- Task 4: operation 3(bending), pieces=20 

Ich muss den Benutzer darauf aufmerksam machen, dass sie auch noch 80 Stücke biegen müssen.

Bisher habe ich es geschafft, alle Arten von Operations für jede Job zur Liste map verwenden, aber jetzt brauche ich alle Teile des Task mit dem gleichen Operation Typ in einem Job zusammenzufassen, und nur für jene Operations in die Tasks gehört dazu Job.

Gibt es eine Möglichkeit, dies unter Verwendung map zu tun? Oder muss ich eine Abfrage manuell schreiben?

EDIT: das ist es, was ich im Moment gepatched habe.

Verfahren operations_applied in Job gibt mir eine Liste von IDs für alle Operations USEND in Tasks für die Job Warteschlange.
Dann gibt mir eine andere Methode, pieces_remaining for(operation) gibt mir die restlichen Stücke für die einzelne operation.
Schließlich in der Job Ansichten, die ich brauche, ich Iterate durch alle operations_applied Drucken alle pieces_remaining_for.
Ich weiß, das ist nicht besonders elegant, aber bisher funktioniert es, irgendwelche Ideen, um das zu verbessern? Danke.

Antwort

0

Wenn ich nicht Mißverständnis bin, ist es nicht möglich, zu tun, was Sie mit map tun wollen, da Karte immer arr.size == arr.map {...}.size gilt und Sie möchten Ihre Array reduce.

Was Sie tun können, ist so etwas wie dieses:

job = Jobs.first 

operation_pieces = {} 
job.tasks.each do |task| 
    operation_pieces[task.operation.id] ||= { operation: task.operation } 
    operation_pieces[task.operation.id][:pieces] ||= 0 
    operation_pieces[task.operation.id][:pieces] += task.pieces 
end 

Jetzt operation_pieces enthält die Summe pieces für den Betrieb mit dem id des jeweiligen Index. Aber ich bin sicher, dass es eine elegantere Version, dies zu tun;)

EDIT: verändert den Code Beispiel auf einen Hash

EDIT: und hier ist die elegantere Version:

job = Jobs.first 
job.tasks 
    .group_by(&:operation) 
    .map { |op, tasks| 
     { op => tasks.sum(&:pieces) } 
    } 

Die group_by gruppiert Ihr Aufgabenfeld durch die Operation der Aufgabe (vielleicht müssen Sie stattdessen group_by { |t| t.operation } verwenden, ich bin mir nicht sicher) und innerhalb der map wird danach die pieces von jeder Aufgabe mit der gleichen Operation summiert. Schließlich erhalten Sie einen Hash des Typs OPERATION => PIECES_SUM (INTEGER).

+0

Danke, das ist viel besser als meine gepatchte Lösung! –

0

Ich nehme die folgenden Variablen für die Abfrage erforderlich,

Attribute Aufgabe: number_of_pieces, Job: Name, Operation: Name

Job.joins("LEFT JOIN tasks ON jobs.id = tasks.job_id").joins("LEFT JOIN operations ON operations.id = tasks.operation_id").select(" SUM(tasks.number_of_pieces) as number_of_pieces, operations.name, jobs.name").group("operations.id, jobs.id") 

Diese Liste wird alle Jobs und die Summe der Teile, die für jede Operation darunter benötigt werden.

, wenn Sie die job_id haben für Sie die Liste der Operationen und die Stücke wollen, dann den Code unten verwenden,

Job.find(params[:job_id]).joins("LEFT JOIN tasks ON jobs.id = tasks.job_id").joins("LEFT JOIN operations ON operations.id = tasks.operation_id").select(" SUM(tasks.number_of_pieces) as number_of_pieces, operations.name, jobs.name").group("operations.id, jobs.id") 

bitte eine Erklärung setzen in den Kommentaren, wenn Ihr Bedarf.

+0

Danke, aber ich hatte gehofft zu vermeiden, SQL zu verwenden ... siehe meine Bearbeitung für meine weitere Vorgehensweise bei dem Problem –

+0

Ich denke, dafür müssen Sie die Struktur der Datenbank umgestalten. Job und Operation haben keine Beziehung zwischen ihnen. Dies ist ohne SQL-Abfragen nicht möglich. –