2017-01-30 5 views
1

Ich habe Auftragsmodell und ein Container-Modell mit einem Rahmen, wie nachstehend:Rails aktiver Bereich Datensatz basierend auf Anzahl des has_many Umfangs

class Order < ActiveRecord::Base 
    has_many :containers, inverse_of: :order, dependent: :destroy 
end 

class Container < ActiveRecord::Base 
    scope :full_pickup_ready, -> { where.not(full_pickup_ready_date: nil) } 
end 

Die Reihenfolge Modell quantity einen Feldaufruf aufweist, die die Menge von Behältern repräsentieren die Reihenfolge erfordert aber nicht notwendigerweise die Größe der Containerverknüpfung, da nicht alle Containerdaten zum Zeitpunkt der Auftragserstellung eingegeben wurden.

Ich möchte einen Bereich auf dem Bestellmodell basierend darauf haben, ob die Anzahl der Container mit einem full_pickup_ready_date kleiner als das Mengenfeld der Bestellung ist.

Ich weiß, dass ich in der Größenordnung Modell fusionieren können den Umfang auf die Behälter wie diese zuzugreifen:

def self.at_origin 
    joins(:containers).merge(Container.full_pickup_ready).uniq 
end 

aber wie kann ich den Umfang Aufträge beschränken, in denen die Gesamtzahl der Behälter mit einem full_pickup_ready_date ist weniger als das mengenfeld auf der bestellung?

UPDATE: dies ziemlich nahe ist, aber ich glaube nicht, mit der select effizient ist:

includes(:containers).select {|o| o.containers.full_pickup_ready.size < o.quantity } 
+0

Was ist das 'Objekt carrier_collected_full'? Ist es eine Sammlung oder nur ein Container? – kurenn

+0

Sorry, das war ich kopiere den falschen Bereich (ich habe mehrere Bereiche mit einem ähnlichen Problem). Es sollte der Bereich im Containermodell 'full_pickup_ready' sein.Ich habe das obige geändert, um den 'full_pickup_ready'-Bereich zu verwenden. –

Antwort

2

Wenn Sie bereit sind, die Wiederverwendung des Anwendungsbereichs auf Container zu verzichten, dann sollten Sie in der Lage sein, etwas zu verwenden wie:

# scope on Order 
joins(:containers) 
    .group("orders.id") 
    .having("count(CASE WHEN full_pickup_ready_date THEN 1 END) < orders.quantity") 
+0

Danke - mit der CASE innerhalb der Zählung ist schlau und gibt mir genau das, was ich will. Ich musste es in 'CASE WHEN wenn Full_pickup_ready_date IST NICHT NULL DANN 1 END' ändern, aber ansonsten perfekt. Ich werde das Kopfgeld vergeben, wenn es mich lässt (in etwa 7 Stunden) –

1

Ich glaube, Sie brauchen diese SQL-Abfrage zu bekommen für Sie zu arbeiten. Die Idee ist also, die SQL-Abfrage richtig zu machen und sie dann in "Rails" zu übersetzen.

SQL

Wenn ich richtig bin, sollte dies die SQL-Abfrage, die Sie erreichen wollen, sein. Vielleicht können Sie versuchen es in Ihrem rails db

SELECT orders.* 
FROM orders JOIN containers 
WHERE containers.id = orders.id 
AND ( 
    SELECT COUNT(containers.id) 
    FROM containers 
    WHERE containers.full_pickup_ready_date IS NOT NULL 
) < orders.quantity; 

Active

Wenn dies die richtige Abfrage ist, dann können wir dies mit Schienen tun

Order.joins(:containers).where("(SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL) < orders.quantity") 

Dies sollte eine Active Beziehung zurück. Sie könnten auch dies tun:

sql = %{ 
    SELECT orders.* 
    FROM orders JOIN containers 
    WHERE containers.id = orders.id 
    AND ( 
    SELECT COUNT(containers.id) 
    FROM containers 
    WHERE containers.full_pickup_ready_date IS NOT NULL 
) < orders.quantity; 
}.gsub(/\s+/, " ").strip 

Order.find_by_sql(sql) 

Fügen Sie einfach diese in einer Klassenmethode (besser als Rahmen IMHO) und Sie sind gut zu gehen.

Also, sollten Sie Ihre Order-Klasse wie folgt aussehen:

class Order < ActiveRecord::Base 
    has_many :containers, inverse_of: :order, dependent: :destroy 

    def self.gimme_a_query_name 
    joins(:containers).where("(SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL) < orders.quantity") 
    end 

    def self.gimme_another_query_name 
    sql = %{ 
     SELECT orders.* 
     FROM orders JOIN containers 
     WHERE containers.id = orders.id 
     AND ( 
     SELECT COUNT(containers.id) 
     FROM containers 
     WHERE containers.full_pickup_ready_date IS NOT NULL 
    ) < orders.quantity; 
    }.gsub(/\s+/, " ").strip 
    find_by_sql(sql) 
    end 
end 

Ich habe keine Möglichkeit, dies zu versuchen, aber es sollte mit wenigen zwicken arbeiten, um die SQL-Abfrage richtig zu machen.

Ich hoffe diese Hilfe!

+0

Danke, ich kann sehen, wie das geht, aber die Antwort von @gwcodes ist ein bisschen prägnanter, also werde ich mit diesem gehen. –

Verwandte Themen