Rails 3: How to identify after_commit action in observers? (create/update/destroy)

前端 未结 9 1477
慢半拍i
慢半拍i 2021-01-30 02:17

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

9条回答
  •  萌比男神i
    2021-01-30 02:41

    I'm curious to know why you couldn't move your after_commit logic into after_create and after_update. Is there some important state change that happens between the latter 2 calls and after_commit?

    If your create and update handling has some overlapping logic, you could just have the latter 2 methods call a third method, passing in the action:

    # Tip: on ruby 1.9 you can use __callee__ to get the current method name, so you don't have to hardcode :create and :update.
    class WidgetObserver < ActiveRecord::Observer
      def after_create(rec)
        # create-specific logic here...
        handler(rec, :create)
        # create-specific logic here...
      end
      def after_update(rec)
        # update-specific logic here...
        handler(rec, :update)
        # update-specific logic here...
      end
    
      private
      def handler(rec, action)
        # overlapping logic
      end
    end
    

    If you still rather use after_commit, you can use thread variables. This won't leak memory as long as dead threads are allowed to be garbage-collected.

    class WidgetObserver < ActiveRecord::Observer
      def after_create(rec)
        warn "observer: after_create"
        Thread.current[:widget_observer_action] = :create
      end
    
      def after_update(rec)
        warn "observer: after_update"
        Thread.current[:widget_observer_action] = :update
      end
    
      # this is needed because after_commit also runs for destroy's.
      def after_destroy(rec)
        warn "observer: after_destroy"
        Thread.current[:widget_observer_action] = :destroy
      end
    
      def after_commit(rec)
        action = Thread.current[:widget_observer_action]
        warn "observer: after_commit: #{action}"
      ensure
        Thread.current[:widget_observer_action] = nil
      end
    
      # isn't strictly necessary, but it's good practice to keep the variable in a proper state.
      def after_rollback(rec)
        Thread.current[:widget_observer_action] = nil
      end
    end
    

提交回复
热议问题