Debugging Smarter: When AI Misses the Mark
How I solved a tricky bug in my Rails app by ditching AI and going old-school.
Yesterday, I ran into a frustrating bug while working on a feature in my Rails app. Naturally, I was tempted to throw the problem at Claude AI and let it do the heavy lifting. But I had a hunch that it was a dead end.
What followed was a deep dive into problem-solving that proved why sometimes, intuition and good old-fashioned research beat AI-driven suggestions.
The Bug
I had just added a migration to introduce a new column to an existing table. When I ran rails db:migrate
, I noticed that the schema version had changed, and the queue schema had also been updated. That’s when I realized I had forgotten to update the schema after upgrading Rails and again after adding Solid Queue. I did not want to lump all these schema changes into one commit.
So, I rolled back my feature changes and reset my database:
rails db:drop
rails db:create
rails db:migrate
That’s when the error hit me:
StandardError: An error has occurred, this and all later migrations canceled:
Undeclared attribute type for enum 'meeting_status' in Match. Enums must be backed by a database column or declared with an explicit type via `attribute`.
The error suggested that every enum in a model must have a corresponding database column. But that didn’t make sense—I had definitely created the necessary columns when adding enums.
What was even stranger was that the failing migration wasn’t introducing a new enum; it was just modifying a column default.
So why was this breaking now, after running smoothly for over a year?
Why I Chose to Solve It Without AI
I suspected the recent Rails upgrade (from 7.0 to 7.2) had something to do with the issue. The problem with using AI for debugging in such cases is that it lacks awareness of my exact Rails upgrade path, my project history, and subtle framework changes.
So instead of asking Claude, I decided to go manual and see if I could trace the problem myself.
How I Found the Solution
I turned to Google, pasting the error message into the search bar. Among the results, I found a GitHub issue titled "Rails 7.1 can't define enums for attributes that don't exist in the table." That sounded familiar.
Seventeen comments in, I found someone describing the exact issue I was facing:
We have a model where we added an enum column in a migration long after the original table was created. This now creates a problem where we cannot run our migrations for an empty database, as the model defines the enum, but the column backing it doesn’t exist in the DB until the migration runs.
Then, a Rails core team member dropped two key insights:
"Accessing models in migration is an anti-pattern precisely because it introduces these kinds of issues."
"There is absolutely no reason to run 3-year-old migrations. Use
db:schema:load
to directly start from a recent state. Old migrations are meant to be deleted."
That was the lightbulb moment.
I had unknowingly been violating a Rails convention by calling models in migrations.
I wasn’t familiar with
db:schema:load
, so I looked it up in the Rails migration guide. That’s when I learned that instead ofdb:drop db:create db:migrate
, I should have been usingdb:reset
ordb:schema:load
to reset my database properly.
How AI Tried to Solve It
Claude 3.5’s Approach
Curious to see what AI would do, I asked Claude 3.5 Sonnet to debug the issue. It first suggested creating a migration to explicitly set the column type for the enum, assuming the error was due to a missing type definition.
When I pointed out that I had been using db:drop db:create db:migrate
for years without issues and that I had upgraded Rails recently, Claude acknowledged my insight but still suggested creating another migration to fix the enum definition.
That wouldn’t work—the original migration was failing, so I couldn’t just patch over it.
Claude then suggested modifying the failing migration, which I rejected because editing old migrations is bad practice. It later proposed commenting out the enum in the model, running migrations, then adding the enum back later. While technically viable, this was an impractical manual workaround.
Its final suggestions involved advanced workarounds using initializers and concerns to bypass model-loading issues. But none of its solutions addressed the real problem—my incorrect database reset workflow.
Claude 3.7’s Approach
With Claude 3.7 Sonnet’s release, I reran the problem to see if it handled things better. This time it also had web access.
While it largely suggested the same solutions as 3.5, it introduced three additional approaches:
Using a custom migration class that doesn’t load the application models, avoiding issues caused by enum definitions before schema changes are applied.
Using a database dump for development via
pg_dump
.Switching from
schema.rb
tostructure.sql
and then using dumps instead of migrations for rebuilding databases.
While the database dump approach aligns with my solution using db:reset, Claude’s explanation made it seem overly complicated and non-idiomatic to Rails, which would have made me hesitant to adopt it.
Why AI Fell Short
Claude missed two critical pieces of context:
The GitHub discussion that led me to the correct solution.
That my workflow (
db:drop db:create db:migrate
) was incorrect and should be replaced withdb:reset
.
If I had relied entirely on Claude, I might have ended up with a workaround instead of a real fix. AI can assist in debugging, but it isn't a substitute for deep problem-solving. Yet.
Claude will still be my go-to, but now I can smell a problem and be confident that going old school would serve me better.