2012-11-05 15 views
6

Ich arbeite an einer Rails 3.2.8-Anwendung, die eine homegrown REST API verwendet, um neue Daten einzufügen. Die Einfügelogik ist für jeden Endpunkt generisch und führt ganz einfach zu einem Aufruf von Model.save.Rails Override speichern, um selektives Update durchzuführen

Für einen der Modelltypen möchte ich zuerst prüfen, ob ein bereits existierender Datensatz vorhanden ist und wenn ja, im Gegensatz zum Einfügen aktualisieren. Wenn der Code mir erlauben würde, auf der Controller-Ebene zu interagieren, wäre dies durch die Verwendung von find_or_create_by einfach, aber meine einzige Option besteht darin, die Speichermethode im Modell zu überschreiben oder einen before_save Callback zu verwenden.

Ich kämpfe um herauszufinden, wie dies funktioniert, da alle Aufrufe zu speichern oder update_attributes innerhalb des Modells führt zu einer Endlosschleife (aus offensichtlichen Gründen).

Gibt es eine Möglichkeit, entweder vor_Speichern oder Speichern so zu überschreiben, dass ich zuerst prüfen kann, ob ein Datensatz mit den Attributen x und y existiert und diesen Datensatz dann abruft und die Aktualisierung vornimmt, ansonsten mit a vorwärts gehen Standard ActiveRecord speichern?

Hier ist mein Code, wie es derzeit in der Activity-Modell steht, die nicht aufgrund Problem der unendlichen Schleife funktioniert:

def save 
    a = UserActivity.find_or_initialize_by_user_id_and_activity_id(user_id: user_id,  activity_id: activity_id) 
    a.update_attributes start_at: start_at, end_at: end_at..... 
end 
+0

Ich fühle mich zu vermeiden, wie die Bearbeitung 'save' könnte eine ganze Dose Würmer von heiklen Problemen mit der Datenbank öffnen. Haben Sie in Erwägung gezogen, einfach 'if - else'-Anweisungen in Verbindung mit' update_attributes' und 'save' zu ​​verwenden? –

Antwort

7

Sie scheinen find_or_create_by_* Methode werden zu müssen.

die Schleife zu vermeiden, sollten Sie diese Methode in save nicht vergeben, sondern in einem dieser beiden Orte:

Option 1: Controller Ebene

In Ihrem Controller, wo Sie diese UserActivity Instanz instanziiert, Sie stattdessen schreiben:

a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id, activity_id: activity_id) 
a.update_attributes start_at: start_at, end_at: end_at..... 

Option 2: Klasse Methode

Wenn Sie sich finden, eine den obigen Code dding auf mehrere contrllers, wäre ein besserer Weg, um eine neue Klasse Methode in UserActivity zu definieren:

class UserActivity 
    def self.create_or_update_from_attrs(user_id, activity_id, start_at, end_at...) 
    a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id,  activity_id: activity_id) 
    a.update_attributes start_at: start_at, end_at: end_at..... 
    end 
end 

Und in den Controllern, offensichtlich:

UserActivity.create_or_update_from_attrs(...) 

Aufschalten speichern

Of Natürlich können Sie die save Methode auch überschreiben, aber dies verdoppelt Rails Funktionalität (find_or_create_by...) und als solche verletzt DRY und Sie könnten sich in schießen Ihr Fuß einige Zeit später, wenn diese Konflikte mit einer anderen Situation, die Sie in laufen, so entmutigen ich die Verwendung dieses:

EDIT: aktualisiert Endlosschleife

class UserActivity 
    def save 
    # If this is new record, check for existing and update that instead: 
    if new_record? && a = UserActivity.where(user_id: user_id, activity_id: activity_id).first 
     a.update_attributes start_at: start_at, end_at: end_at ... 
     return true # just to comply with Rails conventions   
    else 
     # just call super to save this record 
     super 
    end 
    end 
end 
+0

Danke Laas. Das Problem ist, dass die API-Schicht generisch ist und einfach das Speichern von jedem Modell aufruft, das sie als beteiligt interpretiert (basierend auf dem URI-Aufruf). Also, ich habe keinen Haken an der Controller-Schicht, die ich stimme ist der richtige Ort, um diese Logik zu setzen.An dem Punkt, an dem ich beteiligt bin, wurde die Speichermethode bereits am Modell aufgerufen. Ihre Option zum Überschreiben des Speicherns führt immer noch zu einer Endlosschleife, da update_attributes dazu führt, dass das Speichern im Modell erneut aufgerufen wird. – JaySquat

+0

Ich habe meinen Code aktualisiert - der zweite Speicher sollte 'super' heißen, weil der Datensatz nicht' new_record? 'Mehr ist. – Laas

+0

Das hat perfekt funktioniert, danke! Ich würde dich wählen, aber ich habe noch nicht genug Rep. – JaySquat

Verwandte Themen