Debugging Rails Data Bugs with RubyMine Conditional Breakpoints
Stop execution only when a Rails value looks wrong. Use RubyMine conditional breakpoints and live expression evaluation to inspect bad records without temporary logging.
09 Sept 2025, 01:33 UTC

When Logging Turns Into Noise
You know the bug is real because a customer saw it, but your logs only capture a snapshot: one order total is wrong out of thousands. Adding puts or logger.debug feels like fishing in the dark. You restart the server, trigger the request, scroll through hundreds of lines, and hope the right record appears. There is a tighter loop available: stop execution only when the data looks wrong, then inspect the live object state without editing a file.
Conditional Breakpoints: Stop Only on the Bad Record
A standard breakpoint stops every time execution reaches that line. In a Rails request, a model callback, or a loop over records, that means hundreds of suspensions. A conditional breakpoint attaches a Ruby expression to the breakpoint. The debugger evaluates the expression when the line is reached. If the result is falsey, execution continues silently. If it is truthy, the debugger suspends.
Imagine an Order model with many LineItem records. A support ticket says one order total is negative. You suspect the corruption happens in LineItem#discounted_price. Place a breakpoint on the first line of that method and attach a condition such as:
price.negative? && order.legacy_discount?
The exact expression depends on your domain model. The point is that the breakpoint stays silent for healthy records and stops only for the suspicious case.
Inspecting Live State Without Editing Code
Once suspended, the variables pane shows local variables, the receiver (self), and instance variables. For a Rails model, you can expand associations, check params, and verify intermediate values before a save or render. The Evaluate Expression tool runs arbitrary Ruby in the current context. You can test a hypothesis—such as line_items.select { |li| li.price.negative? }—without adding a temporary line to the method and restarting the server.
This matters because Ruby's dynamism makes static reading hard. Concerns, service objects, and metaprogramming can hide where a value actually changes. The debugger shows the runtime state, not a source-level guess.
Rails Navigation as a Shortcut
RubyMine's Rails awareness helps you reach the likely source line faster. If a spec fails on a serializer field, you can often jump from the stack frame to the model or view helper using project symbols rather than grepping for method names. That assumes the project is indexed and the directory is not marked ignored. If navigation misses a symbol, verify the project's Ruby SDK and Rails version in settings so code insight uses the same gemset as the application.
Where the Debugger Fights Back
The main limitation is Ruby's dynamism. Breakpoints inside methods created by define_method, method_missing, or heavy metaprogramming may not bind where you expect. Generated code and ignored files can also hide symbols from navigation. If a breakpoint is not hit, confirm the file is indexed and not excluded before assuming the code path is dead.
Debugging adds overhead and can change timing-sensitive behavior. Remove temporary breakpoints before committing. Remote, Docker, or non-standard process debugging may require additional run-configuration setup beyond a local Rails server, and some setups require RubyMine's debugger gems in the selected SDK or gemset. Exact menu names and shortcuts vary by RubyMine version and platform, so rely on your keymap rather than memorized paths.
| Use case | Better tool | Why |
|---|---|---|
| Production telemetry | Logging | Persistent, low overhead, no interactive session |
| Local reproduction of a wrong value | Debugger | Inspect live state without code edits |
| Timing-sensitive race conditions | Logging | Debugger overhead can alter behavior |
| One-off data corruption | Debugger | Stop exactly on the bad record |
A Practical Sequencing Rule
The engineering decision is not debugger versus logging but sequencing. Use logging for production telemetry and the debugger for local reproduction. Once you know the cause, promote the temporary breakpoint into a regression test. That converts a manual inspection into a permanent guard.
To check the workflow on your machine, create a tiny Ruby or Rails reproducer with a known wrong value. Set a conditional breakpoint and run it in debug mode. Confirm the breakpoint suspends only when the condition is true and that Evaluate Expression returns the expected value for the known case. If it does not, check indexing and SDK alignment first.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.