2012-07-27 17 views
6

Mam formularz rejestracyjny.Szyny 3: wycofanie dla after_create

Gdy użytkownik się zarejestruje, aplikacja ma zapisać dane w tabeli enrollments oraz w tabeli. (Potrzebuję tej separacji, ponieważ profil użytkownika może się zmienić, ale dane, które wprowadził do tej konkretnej rejestracji, muszą zostać zarchiwizowane, więc nawet jeśli później użytkownik zmieni swoje nazwisko, w formularzu rejestracji otrzymam jego wstępne informacje.)

Więc myślałem o zapisywanie danych w tabeli enrollments następnie mają after_create rozmowę, jak to ...

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 

problem jest, co jeśli nie oszczędzając użytkownikowi jakiegokolwiek powodu. Jak mogę przywrócić i zniszczyć właśnie zapisane dane ze stołu enrollments?

+0

Czy użytkownik może zapisać kilka razy? Jeśli nie, po prostu dodaję dodatkowe pola bezpośrednio do tabeli użytkowników. –

+0

Właściwie to rodzic/opiekun zapisujący dziecko do przedszkola. Więc tak, rodzic może zapisać dziecko kilkakrotnie. – leonel

+0

Dla mnie wygląda na to, że umieszczenie save_corresponding_user w after_create będzie problemem. Co się stanie, gdy użytkownik zarejestruje się ponownie? Nie chcesz utworzyć dla nich nowego obiektu użytkownika. Czy tabela rejestrowania prawdopodobnie nie zawiera kolumny user_id? To nie zostanie wypełnione w powyższym kodzie. Gdyby to był ja, po prostu owinąłbym formularz rejestracji i użytkownika w transakcji, która zajmie się wycofaniem obu w przypadku błędu. –

Odpowiedz

12

after_create jest częścią transakcji, która zapisuje bieżący model. Dlatego jeśli Twój kod ulegnie awarii lub jeśli after_create zwróci wartość false, powinna wycofać bieżącą transakcję i unieważnić zapisanie enrollment.

Jeśli chcesz symulować to, dodać do swojej after_create i sprawdzić, czy wszystko działa zgodnie z oczekiwaniami:

raise Exception.new("CRASH") 
+0

Cofanie zmian nie występuje, jeśli używasz bazy danych innej niż transakcyjna, np. Mongodb –

+3

. Jeśli after_create zwraca wartość false, to nie wygląda na wycofanie transakcji (tylko wyjątek). Przynajmniej w Railsach 4. – djburdick

+0

@djburdick Domyślnie transakcja powinna być wycofywana tylko w przypadku zgłoszenia wyjątku. To jest oczekiwane zachowanie. Myślę, że ta odpowiedź jest nieco błędna w odniesieniu do tego szczegółu. – leishman

1

Jak @anthonyalberto wspomniano, after_create jest już częścią transakcji. Aby zdefiniować transakcję należy użyć coś takiego w swoim kontrolerze:

Enrollment.transaction do 
    @enrollment.save! 
end 

To naprawdę wszystko, co trzeba zrobić, jeśli Zapisz wpisu nie powiedzie się lub Zapisz użytkownika nie będzie cofnąć całą transakcję. Oto więcej informacji: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

7

Powracanie false z after_create nic nie da.

Cały łańcuch wywołań zwrotnych jest zawijany w transakcji. Jeśli jakakolwiek metoda wywołania zwrotnego zwróci dokładnie false lub zgłosi wyjątek, łańcuch wykonawczy zostanie zatrzymany i zostanie wydane polecenie ROLLBACK; po wywołaniach zwrotnych można to osiągnąć jedynie poprzez zgłoszenie wyjątku.

Ponadto musisz raise ActiveRecord::Rollback:

Każdy wyjątek, który nie ActiveRecord :: przywracania zostanie ponownie podniesiony przez Rails po łańcuch zwrotna jest zatrzymany. Zgłaszanie wyjątku innego niż ActiveRecord :: Cofanie może złamać kod, który nie oczekuje takich metod jak save i update_attributes (które zwykle próbują zwrócić wartość true lub false), aby podnieść wyjątek.

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

zrobić coś takiego:

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

dla szyn 3: http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#halting-execution