2016-04-29 4 views
1

Ich habe eine einfache Active Abfrage nach dem Vorbild dieser:Wie filtert man ein ActiveRecord-Abfrageergebnis durch Vergleich mit einer anderen Modellinstanz?

similar_changes = Notification.where(change_owner: 'foo1', change_target: 'foo2', change_cancelled: false) 

Jede Meldung Objekt hat ein Feld change_type und ich habe eine andere Funktion, die für die inversen Änderungen (Änderungen, die jeweils eine Mitteilung der change_type mit einer anderen Mitteilung prüft rückgängig machen andere im Zusammenhang mit meiner Bewerbung).

Ich muss diese Benachrichtigung change_type nehmen und vergleichen Sie sie mit allen anderen im Array. Ich muss auf die Objekte wie folgt verweisen: similar_changes[0]['change_type'] wobei der erste Index jedes ActiveRecord im Array ist und das zweite ist das Wörterbuch, das angibt, welche Eigenschaft im Notification-Objekt.

Ich habe ein Gefühl, das ich diese manuell mit zwei verschachtelten Schleifen und if-Anweisungen tun könnte, aber ich weiß auch, Ruby und ich so das Gefühl ist etwas, das es in gebaut haben soll.

Bin ich falsch, oder ist gibt es einen besseren Weg, dies zu tun?

Hier ist der Code (beachten Sie diese alle Code nicht ganz so mit mir tragen fertig ist, wenn es nicht perfekt ist):

def self.group_similar_changes(owner, target, change_type) 
    # long query where it selects all rows where change_owner and change_target 
    # are the same as original   
    # also where cancelled is false 
    # determine if cancelled (yaml) 
    # if cancelled (do nothing) 
    similar_changes = Notification.where(
    change_owner: owner, 
    change_target: target, 
    change_cancelled: false 
) 
    similar_changes.each do |change| 
    cancel_inverse_change(change, change.change_type) 
     if change.cancelled? 
     similar_changes.delete(change) 
     end 
    end 
    end 
end 

def cancel_inverse_change(change, change_type) 
    if change.inverse?(change_type) 
    change.cancel 
    end 
end 

def inverse?(possible_inverse_change) 
    is_inverse = false 
    change_types = YAML.load_file(File.join(NotificationManager::Engine.root, 'config/change_types.yaml')) 
    if self.change_type == change_types[possible_inverse_change]['inverse'] 
    is_inverse = true 
    end 
    return is_inverse 
end 
+0

Nein, es gibt keine Ruby-Magie, dies zu tun. Verwenden Sie Schleifen. – meagar

+1

Woher kommt das "Inverse" in "Return Inverse"? auch change_types vs change_type –

+0

Ah, tut mir leid. Das ist ein Tippfehler, Entschuldigung. –

Antwort

1

Ja, Ihre Schleife über similar_changes verbessert werden kann.

  • Es ist verwirrend, das Array zu ändern, das Sie durchlaufen. Ich weiß nicht einmal ob es zuverlässig ist, weil ich es nie mache!
  • Es ist auch nicht idiomatische Ruby, sich auf den Rückgabewert each zu verlassen. each wird normalerweise verwendet, um etwas mit den bereits existierenden Elementen einer Enumerable zu tun, daher erscheint es seltsam, seinen Rückgabewert zu verwenden.

ich es als

schreiben würde
similar_changes.reject do |change| 
    cancel_inverse_change(change, change.change) 
    change.cancelled? 
end 
+0

Ich nehme an, dass die Reject-Methode das Element entfernt, wenn es T/F ist? –

+0

Ja, 'reject' löscht Elemente, für die der Block true zurückgibt. –

+0

genial, ich werde diese in meinen Code arbeiten und wenn ich es gut funktionieren kann, werde ich die Antwort auswählen. Vielen Dank für Ihr Feedback :). –