Use on load hooks then backtracing for debugging

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the rails category.

Last Updated: 2021-05-15

After the Rails 6 upgrade to Zeitwerk I got this warning upon booting:

DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper.

The thing was, I had no reference to those entities in my env files or initializers. Indeed, I wasn't even using ActionText at all.

In a moment of highly inefficient desperation, I commented out all my initializers and most of my env files... yet the bug persisted.

Researching it today, I stumbled across a better way to debug the issue. What this does is fire the code in the block the first time action_controller_base is loaded. Then a set of filters are added to a backtrace object, and finally the backtrace – from the point of view of the first load of action_controller_base - is gotten (with caller) and filtered (with bc.clean(caller)).

ActiveSupport.on_load(:action_controller_base) do
  bc = ActiveSupport::BacktraceCleaner.new
  bc.remove_silencers!
  bc.add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
  bc.add_silencer { |line| line =~ Regexp.union(
    *(
      %w{ bootsnap railties spring activesupport actionpack zeitwerk thor rack }.
      map{|g| /\A#{g} \([\w.]+\) /}
    ),
    /\Abin\/rails/
  )}

  trace = bc.clean(caller)
  puts "Cleaned backtrace:\n\t#{trace.join("\n\t")}"
  puts "\nMost probably the cause is: #{trace.first}"
  exit(1)
end

Lessons:

References