本文介绍了Rails 3:如何识别观察者中的after_commit动作? (创建/更新/销毁)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个观察者,我注册了一个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动作? (创建/更新/销毁)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-23 20:33