【发布时间】:2011-11-06 12:16:13
【问题描述】:
我有一个观察者,我注册了一个after_commit 回调。
我如何判断它是否在创建或更新后被触发?
我可以通过询问 item.destroyed? 来判断某个项目已被销毁,但 #new_record? 无法正常工作,因为该项目已保存。
我打算通过添加after_create/after_update 并在里面执行类似@action = :create 并检查after_commit 处的@action 来解决它,但似乎观察者实例是一个单例,我可能只需在它到达after_commit 之前覆盖一个值。所以我以一种更丑陋的方式解决了这个问题,在 after_create/update 上根据 item.id 将操作存储在地图中,并在 after_commit 上检查其值。真的很丑。
还有其他方法吗?
更新
正如@tardate 所说,transaction_include_action? 是一个很好的指示,尽管它是一个私有方法,并且在观察者中应该使用#send 访问它。
class ProductScoreObserver < ActiveRecord::Observer
observe :product
def after_commit(product)
if product.send(:transaction_include_action?, :destroy)
...
很遗憾,:on 选项在观察者中不起作用。
只要确保你测试了你的观察者的地狱(如果你使用 use_transactional_fixtures,请寻找test_after_commit gem),所以当你升级到新的 Rails 版本时,你会知道它是否仍然有效。
(在 3.2.9 上测试)
更新 2
我现在使用 ActiveSupport::Concern 而不是观察者,after_commit :blah, on: :create 在那里工作。
【问题讨论】:
-
当 after_commit 被触发时,您是否想知道您的记录是否是新的?重新阅读您的问题和答案,我觉得很困惑。你能改写一下或者给我们一个明确的例子吗?
-
如果您使用单线程服务器,您的初始解决方案确实有效。如果您不使用一个,则切换到一个,例如独角兽,这将以干净的方式解决此问题。它使编程模型变得如此简单,您将不再那么头疼(就像这个一样),并且最终速度更快。使用 +transaction_include_action?+ 并不干净,因为它是不受支持的受保护的 rails 方法,不受 rails 测试套件中的任何测试的支持。下一个版本可能没有那个方法。
-
@elado 我很困惑。接受的答案(迟到的)不适用于观察者(如 ches 的评论所述)。你改用回调了吗?请对您的问题进行解释。
-
@Kelvin,请参阅我关于如何使其与 Observers 一起工作的问题更新。
标签: ruby-on-rails ruby-on-rails-3 transactions observer-pattern