问题描述
我有一个观察者,我注册了一个after_commit
回调.如何确定创建或更新后是否将其触发?我可以通过询问item.destroyed?
来销毁某物品,但是#new_record?
自该物品被保存以来不起作用.
I have an observer and I register an after_commit
callback.How can I tell whether it was fired after create or update?I can tell an item was destroyed by asking item.destroyed?
but #new_record?
doesn't work since the item was saved.
我打算通过添加after_create
/after_update
来解决它,并在内部做类似@action = :create
的操作,并在after_commit
处检查@action
,但是看来观察者实例是单例的,我可能只需在到达after_commit
之前覆盖一个值.因此,我以较丑陋的方式解决了该问题,将操作存储在基于after_create/update上item.id的映射中,并在after_commit上检查了它的值.真丑.
I was going to solve it by adding after_create
/after_update
and do something like @action = :create
inside and check the @action
at after_commit
, but it seems that the observer instance is a singleton and I might just override a value before it gets to the after_commit
. So I solved it in an uglier way, storing the action in a map based on the item.id on after_create/update and checking its value on after_commit. Really ugly.
还有其他方法吗?
正如@tardate所说,transaction_include_action?
是一个很好的指示,尽管它是私有方法,并且在观察者中应使用#send
进行访问.
As @tardate said, transaction_include_action?
is a good indication, though it's a private method, and in an observer it should be accessed with #send
.
class ProductScoreObserver < ActiveRecord::Observer
observe :product
def after_commit(product)
if product.send(:transaction_include_action?, :destroy)
...
不幸的是,:on
选项在观察者中不起作用.
Unfortunately, the :on
option does not work in observers.
只需确保测试了观察者的地狱(如果使用use_transactional_fixtures,请查找test_after_commit
gem),以便在升级到新的Rails版本时知道它是否仍然有效.
Just make sure you test the hell of your observers (look for test_after_commit
gem if you use use_transactional_fixtures) so when you upgrade to new Rails version you'll know if it still works.
(在3.2.9上测试)
(Tested on 3.2.9)
我现在使用ActiveSupport :: Concern代替了观察者,并且after_commit :blah, on: :create
在这里工作.
Instead of Observers I now use ActiveSupport::Concern and after_commit :blah, on: :create
works there.
推荐答案
我认为 transaction_include_action?是你在追求什么.它可以可靠地指示正在处理的特定交易(已在3.0.8中验证).
I think transaction_include_action? is what you are after. It gives a reliable indication of the specific transaction in process (verified in 3.0.8).
通常,它确定事务是否包含针对:create,:update或:destroy的操作.用于过滤回调.
Formally, it determines if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
class Item < ActiveRecord::Base
after_commit lambda {
Rails.logger.info "transaction_include_action?(:create): #{transaction_include_action?(:create)}"
Rails.logger.info "transaction_include_action?(:destroy): #{transaction_include_action?(:destroy)}"
Rails.logger.info "transaction_include_action?(:update): #{transaction_include_action?(:update)}"
}
end
还可能感兴趣的是 transaction_record_state ,它可用于确定记录是在一个记录中创建还是销毁.交易.状态应为:new_record或:destroyed之一.
Also of interest may be transaction_record_state which can be used to determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
Rails 4的更新
对于那些寻求解决Rails 4问题的人,现在不建议使用此方法,您应该使用transaction_include_any_action?
,它接受array
动作.
For those seeking to solve the problem in Rails 4, this method is now deprecated, you should use transaction_include_any_action?
which accepts an array
of actions.
用法示例:
transaction_include_any_action?([:create])
这篇关于Rails 3:如何识别观察者中的after_commit动作? (创建/更新/销毁)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!