While debugging a Rails app, sometimes it's useful to see the full list of callbacks that are set to run before, after, or around a controller action, in the exact sequence they will run. This is especially true in applications with a deep controller inheritance hierarchy or a heavy use of concerns with conditional callbacks.
Here's a small trick you can use to inspect the full list of callbacks for a controller. I just learned this today while trying to make sense of a confusing callback sequence in a fairly complex controller. As always, please let me know if there's a better or more idiomatic way to do this.
First, add a new initializer with the following code under the initializers
directory.
# config/initializers/callbacks.rb
class ActionController::Base
class << self
CALLBACK_KINDS = [:before, :after, :around].freeze
CALLBACK_KINDS.each do |kind|
define_method("#{kind}_actions") do
_process_action_callbacks.select { |c| c.kind == kind }.map(&:filter)
end
end
end
end
If you're not familiar with initializers, check out this post.

The above initializer code loops through the supported kinds of callbacks and uses define_method
to create a method for each one. Inside each method, it filters _process_action_callbacks
by the specific kind and then maps to get the actual method names (or blocks) that will be invoked.
This dynamically defines three methods on every controller class:
before_actions
after_actions
around_actions
Each method returns an array of the corresponding callback methods for that controller, in the order they'll be invoked.
For example, here's the before_action
method the above code will generate:
class ActionController::Base
class << self
def before_actions
filters = _process_action_callbacks.select { |c| c.kind == :before }
filters.map!(&:filter)
end
end
end
Usage
This is how you use the generated methods.
PostsController.before_actions
=>
[:verify_authenticity_token,
:set_site_info,
:configure_permitted_parameters,
:authenticate_user!,
:set_post,
:set_tags]
PostsController.after_actions
=> [:verify_same_origin_request]
PostsController.around_actions
=> [:turbo_tracking_request_id]
This tells you the exact sequence in which your callbacks are run. Very useful when debugging.
How it Works
Internally, Rails stores the list of action callbacks for each controller in a private method called _process_action_callbacks
. Each item in that list is a Callback
object with metadata like:
kind
::before
,:after
, or:around
filter
: the method or block to be calledif
/unless
conditions (as Procs)
Even though it’s not part of the public API, it’s a clean and reliable way to introspect your controller’s filters for debugging or documentation purposes.
Now, often you'll hear that callbacks is a bad practice / anti-pattern. I personally find them very useful to manage side-logic not directly related to the action, just like concerns. Here's a fantastic video from DHH that shows callbacks in the wild, along with some practical and useful commentary on their usage.
Reading the Rails Source Is Worth It.
Reading the Rails codebase, especially the tests, often leads to discovery of simple and useful patterns like this one.
I came across this trick while reading the Rails source code, looking for a built-in way to inspect the callback sequence. There wasn’t a ready-made method, but in filters_test.rb
, I found some test code that did exactly what I needed. From there, it was just a matter of pulling it into an initializer and generalizing it.
If you're ever stuck, or wondering "is there a way to…", a quick dive into the source is often more productive than getting a ready-made answer online.
That's a wrap. I hope you found this article helpful and you learned something new.
As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I reply to all emails I get from developers, and I look forward to hearing from you.
If you'd like to receive future articles directly in your email, please subscribe to my blog. Your email is respected, never shared, rented, sold or spammed. If you're already a subscriber, thank you.