Ich habe ein Modell mit einem after_create Callback. Dieser Rückruf bewirkt, dass ein neuer Datensatz in einem anderen Modell erstellt wird. Wenn jedoch eine Validierung bei der Erstellung des untergeordneten Datensatzes fehlschlägt, wird die ursprüngliche Transaktion weiterhin gespeichert.
Das scheint nicht richtig zu sein. Laut der Rails-Dokumentation ist das Ganze in eine Transaktion verpackt. Mache ich etwas falsch?
class ServiceProvision < ActiveRecord::Base
has_one :cash_receipt
after_create :receive_payment_for_service_provision, :if => Proc.new { |sp| sp.immediate_settlement == true }
private
def receive_payment_for_service_provision
cash_account = CashAccount.find_by_currency_id_and_institution_id( self.currency_id, self.institution_id )
CashReceipt.create( :account_id => account.id, :service_provision_id => self.id, :amount => self.amount, :currency_id => self.currency.id, :cash_account_id => ( cash_account ? cash_account.id : nil ) )
end
end
class CashReceipt < ActiveRecord::Base
belongs_to :service_provision
validates_presence_of :cash_account_id
end
Die CashReceipt schlägt fehl und gibt einen Fehler zurück, wenn seine übergebenen nil für die cash_account_id, jedoch meine neue ServiceProvision Objekt noch gespeichert wird.
it "should fail if a cash account doesn't exist for the currency and institution" do
currency = Factory.create( :currency )
institution = Factory.create( :institution )
service_provision = Factory.build( :service_provision, :currency_id => currency.id, :institution_id => institution.id, :immediate_settlement => true )
service_provision.save.should == false
service_provision.should have( 1 ).error
end
'ServiceProvision service provision creation should raise an error if a cash account doesn't exist for the currency and institution' FAILED expected: false,
got: true (using ==)
Dies scheint im Widerspruch zu den Angaben in den Unterlagen zu stehen
Sowohl Base#save als auch Base#destroy kommen in eine Transaktion verpackt, die sicherstellt dass alles was Sie in Validierungen oder Callbacks geschieht unter dem geschützten Rahmen einer Transaktion geschieht. Also können Sie Validierungen verwenden um nach Werte, von denen die Transaktion abhängt oder Sie können Ausnahmen in den Callbacks zum Rollback auslösen, einschließlich after_* Rückrufe.
Und wenn ich manuell versuchen, die Transaktion in den Rückruf wie so zu stornieren:
cr = CashReceipt.create( :account_id => account.id, :service_provision_id => self.id, :amount => self.amount, :currency_id => self.currency.id, :cash_account_id => ( cash_account ? cash_account.id : nil ) )
unless cr.errors.empty?
errors.add_to_base("Error while creating CashReciept [#{cr.errors}].")
return false
end
dann wird das neue ServiceProvision-Objekt trotzdem gespeichert.