2014-06-14 7 views
15

Wyobraź sobie, że masz 2 modele, osobę i adres, a tylko jeden adres na osobę może być oznaczony jako "główny". Więc jeśli chcę zmienić adres główny osoby, muszę użyć transakcji, aby zaznaczyć nową jako główną i usunąć zaznaczenie starej. I o ile wiem, z wykorzystaniem transakcji w sterownikach nie jest dobre, więc nie mam specjalnej metody w modelu, to jest to co mam:Jak uratować transakcję modelu i pokazać użytkownikowi błąd?

AddressesController < ApplicationController 
def update 
    @new_address = Address.find(params[:id]) 
    @old_address = Address.find(params[:id2]) 
    @new_address.exchange_status_with(@old_address)  
end 
end 

Model:

class Address < ActiveRecord::Base 
    def exchange_status_with(address) 
    ActiveRecord::Base.transaction do 
    self.save! 
    address.save! 
    end  
    end 
end 

Więc thequestion jest, jeśli transakcja w metodzie modelowej nie powiedzie się, muszę ją uratować i powiadomić użytkownika o błędzie, jak to zrobić? Czy istnieje sposób, aby ta metoda modelu zwróciła wartość true lub false, w zależności od tego, czy transakcja zakończyła się powodzeniem, czy nie, na przykład metoda zapisu?

Prawdopodobnie mógłbym umieścić tę transakcję w kontrolerze i wyrenderować komunikat o błędzie w części ratunkowej, ale myślę, że nie jest to właściwe, czy mogę umieścić tę metodę w wywołaniu zwrotnym, ale wyobraź sobie, że jest jakiś powód, dla którego nie mogę tego zrobić. , jaka jest alternatywa?

PS nie zwracać uwagę na znalezieniu wystąpienia z identyfikatorem params i ID2, tylko losowe rzeczy, aby pokazać, że mam 2 instancje

Odpowiedz

35
def exchange_status_with(address) 
    ActiveRecord::Base.transaction do 
    self.save! 
    address.save! 
    end 
rescue ActiveRecord::RecordInvalid => exception 
    # do something with exception here 
end 

FYI wyjątek wygląda następująco:

#<ActiveRecord::RecordInvalid: Validation failed: Email can't be blank> 

oraz:

exception.message 
# => "Validation failed: Email can't be blank" 

marginesie, można zmienić self.save! do save!


Alternatywne rozwiązanie, jeśli chce zachować swoje aktywnego modelu błędy:

class MyCustomErrorClass < StandardError; end 

def exchange_status_with(address) 
    ActiveRecord::Base.transaction do 
    raise MyCustomErrorClass unless self.save 
    raise MyCustomErrorClass unless address.save 
    end 
rescue MyCustomErrorClass 
    # here you have to check self.errors OR address.errors 
end 
+0

Yes..But '' self.save wygląda czysty do mnie .. –

+0

Można [dodać niestandardowy komunikat o błędzie ] (http://guides.rubyonrails.org/active_record_validations.html#errors-base) wewnątrz 'rescue', aby wskazać nieudaną transakcję, błędy można następnie sprawdzić w kontrolerze, patrz http://guides.rubyonrails.org /active_record_validations.html#working-with-validation-errors – Stefan

+0

Dzięki bro, dostałem idealną odpowiedź. –

Powiązane problemy