在after_save回调中返回false和rollback

时间:2012-03-26 17:02:44

标签: ruby-on-rails activerecord

在ActiveRecord模型中,after_save回调我需要ROLLBACK事务并返回false。

def after_save_callback
  if mycondition?
    raise ActiveRecord::Rollback
  end
end

这个回调回滚事务但mymodel.save!返回true。如何让它返回false和rollback?

3 个答案:

答案 0 :(得分:9)

如果要在after_save回调中中止保存,则应该

raise ActiveRecord::RecordInvalid.new(self)

而不是

raise ActiveRecord::Rollback

这不仅会回滚事务(回调总是发生在可能隐式事务中作为savecreate的一部分),还会导致save返回{{1 }}

以下是一篇详细介绍的文章:http://tech.taskrabbit.com/blog/2013/05/23/rollback-after-save/

答案 1 :(得分:5)

def around_save
  ActiveRecord::Base.transaction do
    raise ActiveRecord::Rollback # this will actually ROLLBACK
    yield # calls the actual save method
    raise ActiveRecord::Rollback # this will cause a COMMIT!!! because it affect only this internal transaction.
    # OTHER ACTIONS NOT EXECUTED BUT BEING A INTERNAL TRANSACTION, THE PARENT WILL COMMIT, because parent hasn't failed.
  end
end

所以...我认为around_save已经存在于事务块中,因此您不需要添加额外的ActiveRecord :: Base.transaction do block,因为回滚不会传播

因此,如果要在yield之前或之后回滚,则需要删除该内部事务。

def around_save
  #ActiveRecord::Base.transaction do
    raise ActiveRecord::Rollback # this will actually ROLLBACK
    yield # calls the actual save method
    raise ActiveRecord::Rollback # this will actually ROLLBACK
  # end
end

编辑:阅读我写的内容......现在看起来很难理解。重点是:如果您要使用aroud_save,请不要再使用ActiveRecord::Base.transaction在上一个示例中执行>),因为rails会将调用包装到{{1使用自己的around_save,所以当你ActiveRecord::Base.transaction只回滚最内部的事务时,你可以用outnge结果和部分保存结束(就像在第一个例子中那样失败)。

答案 2 :(得分:-1)

我不认为您可以使用after_save执行此操作。您应该改为around_save

def around_save
  ActiveRecord::Base.transaction do
    yield # calls the actual save method
    raise ActiveRecord::Rollback if my_condition?
  end
end