2012-03-26 75 views
4

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

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

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

回答

-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 
+6

Rails的包装'型号save'反正。你不应该在around_save钩子里面打开第二个事务。相反,你应该提高'ActiveRecord :: Rollback'。 – BBonifield 2013-01-10 00:48:08

4
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_saveActiveRecord::Base.transaction再次wrapp(不喜欢在最后一个例子),因为轨道将包装调用around_save与自己是如此ActiveRecord::Base.transaction当你raise ActiveRecord::Rollback你只回滚最内部交易,所以你可以结束extrange结果和部分保存(如在第一个例子中,这是失败)。

5

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

raise ActiveRecord::RecordInvalid.new(self) 

而不是

raise ActiveRecord::Rollback 

这不仅会回滚事务(回调总是possibly-内发生作为savecreate的一部分的隐式交易),但也导致save返回false

下面是更细节的文章:在一个事务中http://tech.taskrabbit.com/blog/2013/05/23/rollback-after-save/