Daniel Duque
Daniel Duque

Reputation: 133

Using set_callback for after_commit on create

Rails 4.2.6:

I have an after_commit which is defined to only be executed on create by passing on: :create option.

In tests, I'm using skip_callback and set_callback to bypass this execution. However, I'm having issues to use set_callback properly back again as I can't figure out how to provide the on: :create option back.

I've been reading docs but no luck!

Callback definition

after_commit :create_report, on: :create

Skip and Set statements

Order.skip_callback(:commit, :after, :create_report)

Order.set_callback(:commit, :after, :create_report)

Upvotes: 2

Views: 1316

Answers (2)

Ryan O'Donnell
Ryan O'Donnell

Reputation: 481

I ran into this issue as well. I was able to workaround by monkey patching the original class. In your case, it should probably work to do this:

Short answer:

# disable your callbacks
Order.skip_callback(:commit, :after, :create_report)

# do whatever you need to do...

# Restore callbacks with monkey patch
class Order ; after_commit  :create_report, on: :create ; end

Longer answer:

Read on for more detail below:

I was able to figure this out by looking at the __callbacks:

When it's originally defined, it looks like this:

:commit=>
  #<ActiveSupport::Callbacks::CallbackChain:0x00007fbd0aceaf80
   @callbacks=
    #<ActiveSupport::Callbacks::CallbackSequence:0x00007fbd4a2f18b8
     @after=
      [#<Proc:0x00007fbd4a2f0df0@/Users/ryanjodonnell/.rvm/gems/ruby-2.6.5/gems/activesupport-5.2.4.2/lib/active_support/callbacks.rb:256>],
     @before=[],
     @call_template=nil,
     @nested=nil,
     @user_conditions=nil>,
   @chain=
    [#<ActiveSupport::Callbacks::Callback:0x00007fbd0aceb200
      @chain_config=
       {:scope=>[:kind, :name],
        :terminator=>
         #<Proc:0x00007fbd480e0670@/Users/ryanjodonnell/.rvm/gems/ruby-2.6.5/gems/activesupport-5.2.4.2/lib/active_support/callbacks.rb:603>},
      @filter=:create_report,
      @if=
       [#<Proc:0x00007fbd0aceb5c0@/Users/ryanjodonnell/.rvm/gems/ruby-2.6.5/gems/activerecord-5.2.4.2/lib/active_record/transactions.rb:288 (lambda)>],
      @key=:create_report,
      @kind=:after,
      @name=:commit,
      @unless=[]>],

After you disable the callbacks with Order.skip_callback(:commit, :after, :create_report), notice that your callback is now missing as expected:

 :commit=>
  #<ActiveSupport::Callbacks::CallbackChain:0x00007fbd0b672ad0
   @callbacks=nil,
   @chain=[],
   @config=
    {:scope=>[:kind, :name],
     :terminator=>
      #<Proc:0x00007fbd480e0670@/Users/ryanjodonnell/.rvm/gems/ruby-2.6.5/gems/activesupport-5.2.4.2/lib/active_support/callbacks.rb:603>},
   @mutex=#<Thread::Mutex:0x00007fbd0b672a80>,
   @name=:commit>,

Now, re-create the callback with Order.set_callback(:commit, :after, :create_report), you will notice that callback is restored, but missing the @if=[#Proc]

 :commit=>
  #<ActiveSupport::Callbacks::CallbackChain:0x00007fbd0ae90790
   @callbacks=nil,
   @chain=
    [#<ActiveSupport::Callbacks::Callback:0x00007fbd0ae90998
      @chain_config=
       {:scope=>[:kind, :name],
        :terminator=>
         #<Proc:0x00007fbd480e0670@/Users/ryanjodonnell/.rvm/gems/ruby-2.6.5/gems/activesupport-5.2.4.2/lib/active_support/callbacks.rb:603>},
      @filter=:create_report,
      @if=[],
      @key=:create_report,
      @kind=:after,
      @name=:commit,
      @unless=[]>],

Upvotes: 2

Ashik Salman
Ashik Salman

Reputation: 1879

From the after_commit documentation:

Note that transactional fixtures do not play well with this feature. Please use the test_after_commit gem to have these hooks fired in tests.

Upvotes: 0

Related Questions