Return false and rollback in after_save callback

懵懂的女人 提交于 2020-01-22 18:50:14

问题


In ActiveRecord model after_save callback I need to ROLLBACK transaction and return false.

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

This callback rolls-back transaction but mymodel.save! returns true. How to make it return false and rollback?


回答1:


I don't think you can do this with after_save You should be looking at around_save instead:

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



回答2:


If you want to abort a save in an after_save callback, you should

raise ActiveRecord::RecordInvalid.new(self)

rather than

raise ActiveRecord::Rollback

This will not only roll back the transaction (callbacks always happen inside a possibly-implicit transaction as part of the save or create) but also cause save to return false.

Here is an article with more details: http://tech.taskrabbit.com/blog/2013/05/23/rollback-after-save/




回答3:


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

So... I think around_save come already on a transaction block, so you don't need to add that extra ActiveRecord::Base.transaction do block because rollbacks doesnt propagate up

So if you want to rollback before or after yield, you need to remove that internal transaction.

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

EDIT: Reading what I wrote... now seem difficult to understand. The point is: if you are gonna use aroud_save don't wrapp again with ActiveRecord::Base.transaction (do like in the last example) because rails will wrap the call to around_save with is own ActiveRecord::Base.transaction so when you raise ActiveRecord::Rollback you are only rolling back the most internal transaction, so you can end with extrange results and partial saves (like in the first example whic is FAIL).



来源:https://stackoverflow.com/questions/9876465/return-false-and-rollback-in-after-save-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!