ruby-on-rails - 为什么回调引用的模型中的验证不会导致我的原始事务失败?

标签 ruby-on-rails validation callback

我有一个带有 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 传递 nil 时,它确实失败并返回错误,但是我的新 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 ==)

这似乎与文档中的这一点相矛盾

Both Base#save and Base#destroy come wrapped in a transaction that ensures that whatever you do in validations or callbacks will happen under the protected cover of a transaction. So you can use validations to check for values that the transaction depends on or you can raise exceptions in the callbacks to rollback, including after_* callbacks.



如果我手动尝试取消回调中的事务,如下所示:
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 对象。

最佳答案

移动 CacheReceipt创建到 before_validation筛选。由于您有 has_one关联ServiceProvision , CacheReceipt对象将具有正确的 :service_provision_id保存后。您的代码如下:

before_validation :receive_payment_for_service_provision, :if => :immediate_settlement?  

def receive_payment_for_service_provision
  cash_account = CashAccount.find_by_currency_id_and_institution_id( self.currency_id, self.institution_id )
  self.cash_receipt.build(:account_id => account.id, 
                          :amount => self.amount, 
                          :currency_id => self.currency.id,  
                          :cash_account_id => ( cash_account ? cash_account.id : nil ) )
end

现在保存在 ServiceProvision实例将返回 false如果在保存关联的 CacheReceipt 时出现错误.

关于ruby-on-rails - 为什么回调引用的模型中的验证不会导致我的原始事务失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2354027/

相关文章:

java - 带有指向结构参数的指针的 JNA 回调函数

ruby-on-rails - 无法使用 rvm 安装从命令行运行 rails

ruby-on-rails - 在模型中使用 accepts_nested_attributes_for 时出现 Rails 4.1 错误

javascript - 在 rails 中为 CKEditor 添加自定义工具栏

用于验证组织/公司编号的 c# 代码?

javascript - "if"验证表单的语句无法正常工作

ruby-on-rails - 为什么大多数 Ruby/Rack 应用程序以这种方式引导?

java - 使用选项的 XSD 验证错误

function - 如何从 Flutter 中的方法获取 AlertDialog 回调?

c++ - 嵌套C++模板定义