09 Sep 2025

How I Debugged Unexpected Attribute Changes in Rails

#ruby-on-rails

I was debugging an issue where a database record’s attribute was getting updated incorrectly. There were lots of callbacks involved, so it was taking time to figure out from where the value was being updated.

I needed a way to see exactly when the attribute was being changed. That’s when I came across ActiveModel::Dirty module. With that, I found the error in no time.

What is ActiveModel::Dirty?

ActiveModel::Dirty lets you track when an object’s attributes change. It provides methods like *_changed?, *_will_change! that track when the value has been modified.

However, this module only tracks in-memory changes, resetting after the object is saved.

In most applications, we often need to know about attributes after they’re saved to the database.

ActiveRecord addresses this by building on the module through ActiveRecord::AttributeMethods::Dirty, providing methods like saved_change_to_* and saved_changes? to track changes across the database lifecycle.

Back to debugging

With this info, I went back to debugging.

The problem was that in a model, the attribute field_id was being assigned an incorrect value. So I used saved_change_to_* method inside an after_save callback. This way, whenever the record was saved, the callback would run.

Here’s the code I used:

after_save -> {
  if saved_change_to_field_id?
    puts "field_id changed from #{saved_change_to_field_id.first} to #{saved_change_to_field_id.last}"
    binding.pry
  end
}

With this in place, I could instantly see whenever field_id changed and pause execution to inspect the call stack. That helped me identify the callback responsible and fix the issue.

Conclusion

It was a delight to learn about this module. It’s super useful for catching data changes. Try it out. It might save you a lot of time the next time your model behaves unexpectedly.


Other Posts you may like

Building a Rails app with Supabase & Render
Add devise to rails app
New Domain Setup Manual: From DNS to Email Routing