2012-07-27 19 views
6

Ich habe ein Anmeldeformular.Schienen 3: Rollback für after_create

Wenn der Benutzer sich anmeldet, soll die App die Daten in der Tabelle und in der users Tabelle speichern. (Ich brauche diese Trennung, weil das Profil des Benutzers sich ändern kann, aber die Daten, die er für diese bestimmte Registrierung eingegeben hat, müssen archiviert werden. Selbst wenn später der Benutzer seinen Nachnamen ändert, habe ich im Anmeldeformular seine ersten Informationen.)

So etwa dachte ich Daten in der enrollments Tabelle Speichern dann einen after_create Anruf haben, so ...

class Enrollment < ActiveRecord::Base 

    after_create :save_corresponding_user 

    def save_corresponding_user 
    user = User.new 
    user.full_name = self.user_full_name 
    user.email = self.user_email 
    user.mobile_phone = self.user_mobile_phone 
    user.save 
    end 
end 

die Frage ist, was passiert, wenn der Benutzer aus irgendeinem Grund ausfällt speichern. Wie kann ich die gerade gespeicherten Daten aus der Tabelle enrollments zurücksetzen und löschen?

+0

ein Benutzer mehrmals einschreiben? Wenn nicht, würde ich einfach die zusätzlichen Felder direkt in der Benutzertabelle hinzufügen. –

+0

Nun, eigentlich ist es ein Elternteil/Erziehungsberechtigter, der ein Kind in eine Kindertagesstätte aufnimmt. Also ja, die Eltern können ein Kind mehrmals anmelden. – leonel

+0

Für mich scheint es, als würde das Setzen von save_corresponding_user in after_create ein Problem sein. Was passiert, wenn sich der Benutzer erneut anmeldet? Sie möchten kein neues Benutzerobjekt für sie erstellen. Hat die Registrierungstabelle wahrscheinlich keine user_id-Spalte? Das wäre oben in deinem Code nicht enthalten. Wenn ich es wäre, würde ich das Erstellen der Registrierung und den Benutzer einfach in eine Transaktion einfügen, die das Zurücksetzen beider im Falle eines Fehlers behandelt. –

Antwort

12

after_create ist ein Teil der Transaktion, die das aktuelle Modell speichert. Wenn der Code abstürzt oder wenn after_create false zurückgibt, sollte daher die aktuelle Transaktion zurückgesetzt und die enrollment-Speicherung ungültig gemacht werden.

Wenn Sie dies simulieren möchten, fügen Sie diese zu Ihrer after_create und sehen, ob alles wie erwartet funktioniert:

raise Exception.new("CRASH") 
+0

der Rollback tritt nicht auf, wenn Sie eine nicht transaktionale Datenbank wie mongodb verwenden –

+3

Wenn After_create false zurückgibt scheint nicht die Transaktion entweder Rollback (nur die Ausnahme). Zumindest in Rails 4. – djburdick

+0

@djburdick Eine Transaktion sollte standardmäßig zurückgesetzt werden, wenn eine Ausnahme ausgelöst wird. Das ist also das erwartete Verhalten. Ich denke, dass diese Antwort bezüglich dieses Details etwas falsch ist. – leishman

1

Wie @anthonyalberto erwähnt, after_create ist bereits Teil der Transaktion. Um eine Transaktion zu definieren würden Sie so etwas in Ihrem Controller verwenden:

Enrollment.transaction do 
    @enrollment.save! 
end 

Das ist wirklich alles, was Sie tun müssen, wenn die Speicherung der Einschreibung fehlschlägt oder die Speicherung von Benutzer versagt wird es rollen Sie Ihre gesamte Transaktion zurück. Hier finden Sie weitere Informationen: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

7

Zurückgeben false von after_create wird nichts tun.

Die gesamte Callback-Kette ist in eine Transaktion eingeschlossen. Wenn irgendeine vor der Callback-Methode genau false zurückgibt oder eine Ausnahme auslöst, wird die Ausführungskette angehalten und ein ROLLBACK ausgegeben. Nach Rückrufen kann dies nur durch Auslösen einer Ausnahme erreicht werden.

Außerdem müssen Sie raise ActiveRecord::Rollback:

Jede Ausnahme, die Activerecord nicht :: Rollback wird durch Rails wieder angehoben werden, nachdem die Rückrufkette angehalten wird. Wenn Sie eine andere Ausnahme als ActiveRecord :: Rollback auslösen, wird möglicherweise Code beschädigt, der keine Methoden wie save und update_attributes erwartet (die normalerweise versuchen, true oder false zurückzugeben), um eine Ausnahme auszulösen.

http://guides.rubyonrails.org/active_record_callbacks.html#halting-execution

ich so etwas tun:

after_create do 
    if condition 
    errors.add(:attr, 'Blah blah blah.') 
    raise ActiveRecord::Rollback 
    end 
end 

Für Rails 3: http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#halting-execution