Halting the callback chains

On this article I will share a technique to find out more about callbacks in Ruby on Rails framework.

Callbacks are a common way of implicitly invoking actions when an event fires inside a system. Many web frameworks like Rails or Laravel depend on this mechanism to handle esoteric events. A chain of callbacks is created when multiple callbacks are being fired one after another. Finally, we will call halting such a chain when we stop the event propagation.

Halting a callback in Rails is simple if we use the abstraction provided by the framework. Specifically, calling

throw :abort

will halt the ActiveRecord callbacks.

In larger Rails systems where legacy code or questionable techniques, like depending in implicit ActiveRecord callbacks for domain specific logic, may have been accumulated, halting and debugging callbacks is not a trivial task. One way to approach such troubleshooting is by learning more about the callbacks of our system. To do that we will use the pry debugger.

The class methods we are looking for is:

_#{action_name}_callbacks # e.g., _destroy_callbacks

Then using select, map and filter I am able to list and iterate over any callback given an ActiveModel class:

User._destroy_callbacks.select {|cb| cb.kind == :after }.map(&:filter)

=>
[
  :destroy_user_friends,
  :build_ast,
  :disconnect_from_bank_system,
  :check_soft_delete,
  ...
]