Ash
Ash

Reputation: 25682

How do ActiveRecord Callbacks actually Work in Rails

I've been through the source code for the ActiveRecord callbacks; and I can see the ActiveRecord Concerns for the callbacks like so:

  module Callbacks
    extend ActiveSupport::Concern

    CALLBACKS = [
      :after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
      :before_save, :around_save, :after_save, :before_create, :around_create,
      :after_create, :before_update, :around_update, :after_update,
      :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
    ]

    def destroy #:nodoc:
      @_destroy_callback_already_called ||= false
      return if @_destroy_callback_already_called
      @_destroy_callback_already_called = true
      _run_destroy_callbacks { super }
    rescue RecordNotDestroyed => e
      @_association_destroy_exception = e
      false
    ensure
      @_destroy_callback_already_called = false
    end

    def touch(*) #:nodoc:
      _run_touch_callbacks { super }
    end

  private

    def create_or_update(*)
      _run_save_callbacks { super }
    end

    def _create_record
      _run_create_callbacks { super }
    end

    def _update_record(*)
      _run_update_callbacks { super }
    end
  end
end

Now I can see that the available callbacks via a constant of an array of symbols.

Further investigation shows that the create_or_update(*) method from the callbacks concern being called from the persistance.rb file (which does the CRUD operations for the model) - and using lines like @_trigger_update_callback = result.

What I cannot figure out, however is 2 key elements.

  1. How/where does ActiveRecord ACTUALLY trigger the callback, and where is that method that yields to the symbol for the method that you pass to the callback to be executed.

  2. How does ActiveRecord know that the callback even exits? That is, how does it go from being a class declaration, to being executed by ActiveRecord? Is it loaded into some kind of register or something checked each load; etc?

Upvotes: 1

Views: 1520

Answers (1)

Simple Lime
Simple Lime

Reputation: 11070

ActiveRecord and ActiveModel use ActiveSupport::Callbacks to do their dirty work.

If you take a look at its ClassMethods module, you'll find define_callbacks which is what defines (through module_eval) _run_update_callbacks and friends. The _run_*_callbacks methods just calls run_callbacks from the main module.

So to answer your questions:

  1. I believe ActiveRecord actually triggers the callbacks in the code you posted. Looks like ActiveRecord::Transactions has a couple that it runs (the transaction related ones, funny enough).

  2. Without digging too deep, it looks like the run_callbacks method just keeps a list of all the callbacks and then goes through and figures out what's what and what to do.

Probably not as in depth of an answer as you were hoping for, but hopefully this can at least get you going in the right direction digging around and investigating on your own.

Upvotes: 2

Related Questions