Debugging a large codebase can sometimes be a pain, especially if you’re new to it and you don’t know about all the classes and relations in the system.
In this post I’d like to share a cool (IMO) way to debug not well-known codebase using dynamically created breakpoints. NB: yes, Ruby is so dynamic that you can create breakpoints on the go.
Assuming that you use byebug or pry, imagine that you’ve put a breaking point:
class PaymentValidator
attr_accessor :credit_card
def initialize(checkout, attributes = {})
self.credit_card = checkout.create_credit_card
binding.pry
end
end
Inside the breaking point, you only know that there is a credit_card
object with errors
method
coming from ActiveModel::Errors.
You also expect that some other objects will be calling errors.add
, but you don’t know who
and how will be doing it.
Here is what you can insert being in the breaking point:
mod = Module.new do
def add(*args)
binding.pry
super
end
end
credit_card.errors.extend(mod)
This snipped will inject into add
method from credit_card.errors
and start debugging when someone
calls that method. Tricky, eh?
In my case, this dynamic breaking point helped me to find which objects have been adding errors on credit_card
object.
As an alternative, I could probably insert a breaking point into the ActiveModel::Errors#add
method,
but that would trigger too many breaking points that I’m not interested in, because ActiveModel::Errors#add
is used in other places of the same system.
Happy debugging!