У меня есть модель с обратным вызовом after_create. Этот обратный вызов вызывает создание новой записи в другой модели. Однако, если проверка не удалась при создании дочерней записи, исходная транзакция все еще сохраняется.
Это не похоже на правду. Согласно документации Rails, все это заключено в транзакцию. Я что-то не так делаю?
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
CashReceipt терпит неудачу и возвращает ошибку, когда ему передан ноль для cash_account_id, однако мой новый объект ServiceProvision все еще сохраняется.
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 ==)
Это, кажется, противоречит этому из документов
Приходят и Base # save, и Base # destroy
завернутый в транзакции, которая обеспечивает
что бы вы ни делали в валидации или
обратные вызовы произойдут под
защищенное покрытие транзакции. Так
Вы можете использовать проверки для проверки
значения, от которых зависит транзакция
или вы можете поднять исключения в
обратные вызовы для отката, в том числе
after_ * обратные вызовы.
И если я вручную попытаюсь отменить транзакцию в обратном вызове, вот так:
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
затем новый объект ServiceProvision все еще сохраняется.