4 Stimmen

Warum führt die Validierung in einem Modell, auf das ein Callback verweist, nicht zum Scheitern meiner ursprünglichen Transaktion?

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X