RubyMine Debugger: Conditional Breakpoints & Evaluate Expression
RubyMine’s integrated debugger turns tedious Rails debugging into a visual, interactive process. Learn how to use conditional breakpoints and Evaluate Expression to pause, inspect, and modify state on the fly.
04 Sept 2025, 15:49 UTC

1. The Problem: Debugging Rails in a Black‑Box Way
When a Rails controller action misbehaves, the usual workflow is to sprinkle puts or logger.debug statements, restart the server, and watch the console. This approach is noisy, slow, and fragile—especially for long‑running loops or background jobs. Developers often need to pause execution at a specific point, inspect nested objects, or change a variable on the fly. RubyMine’s built‑in debugger addresses these pain points by integrating with the debug gem and offering a visual, stateful debugging experience.
2. RubyMine’s Debugger Architecture
RubyMine uses the debug gem (or byebug as a fallback) to hook into the Ruby runtime. When you launch your Rails app in Debug mode, the IDE starts a remote debugging session that listens for breakpoint events. The gem injects a thin adapter into the interpreter, allowing RubyMine to:
- Pause execution when a line is hit.
- Expose the current stack frame and local variables.
- Execute arbitrary Ruby code in the paused context via the Evaluate Expression tool.
For this to work smoothly, the gem version in Gemfile must match the RubyMine version’s supported API. Check the IDE’s Help > About dialog for the required debug gem version.
3. Conditional Breakpoints & Evaluate Expression
Two features lift debugging from a linear to an interactive process:
- Conditional Breakpoints – Instead of stopping on every hit, you can set a Ruby expression that must evaluate to
truefor the debugger to pause. This is invaluable for loops or callbacks where only a specific state is of interest. - Evaluate Expression – While paused, you can run any Ruby code in the current stack frame. This lets you inspect nested objects, call helper methods, or even mutate state to test hypotheses without restarting.
Both features are accessible from the gutter icon next to the line number. Right‑click to add a breakpoint, then select Breakpoint Settings… to add a condition or to enable Evaluate Expression during a pause.
4. Practical Example: Debugging a Validation Loop
Suppose you have a controller that processes a CSV import and validates each row. You want to pause only when a row fails validation.
# app/controllers/imports_controller.rb
class ImportsController < ApplicationController
def create
CSV.foreach(params[:file].path, headers: true) do |row|
record = Record.new(row.to_hash)
unless record.valid?
# <-- breakpoint here
render json: { errors: record.errors.full_messages }
return
end
record.save!
end
render json: { status: 'ok' }
end
end
Steps to debug:
- Install the debug gem in the development group:
Rungroup :development do gem 'debug', require: false endbundle install. - Set a conditional breakpoint on the line marked
# <-- breakpoint here. In RubyMine, right‑click the gutter, chooseBreakpoint Settings…, and enter the condition:
This ensures the debugger only pauses when a record is invalid.!record.valid? - Run the app in Debug mode by clicking the green bug icon or selecting
Run > Debug 'imports#create'. Ensure the Rails server is started with thedebuggem loaded (RubyMine does this automatically). - Trigger the import via a POST request. When the breakpoint fires, the Variables view shows
row,record, andrecord.errors. - Use Evaluate Expression to inspect deeper:
Or modify state:record.errors.full_messages
Then resume execution withrecord.errors.clearContinue.
To verify the breakpoint worked, check the IDE’s console for the pause message and confirm that record.errors is empty after the modification.
5. Trade‑offs & Limitations
- Performance Impact – Debugging a tight loop (e.g., processing thousands of rows) can slow the application by an order of magnitude. Avoid enabling breakpoints inside critical loops unless necessary.
- Gem Compatibility – Using a
debuggem version older than the one required by RubyMine may disable conditional breakpoints or cause the IDE to ignore breakpoints entirely. Always keep the gem in sync with the IDE. - Multi‑threaded Code – In background jobs or multi‑threaded controllers, a breakpoint may pause one thread but not others, leading to race conditions. Use thread‑specific breakpoints or isolate the code path you want to debug.
- Limited to Ruby 3.1+ – The integrated debugger relies on the
debuggem’s API, which is only available for Ruby 3.1 and newer. On older Ruby versions, you’ll need to fall back tobyebugwith reduced feature support.
6. Actionable Takeaway
By leveraging RubyMine’s conditional breakpoints and Evaluate Expression tool, you can:
- Stop execution only when the exact state you care about occurs.
- Inspect and mutate complex objects without re‑running the code.
- Reduce noisy log output and accelerate the debugging cycle.
Next step: add a debugger line in your controller, launch the app in Debug mode, and watch RubyMine pause automatically. From there, experiment with conditions and evaluate expressions to get comfortable with the flow. Happy debugging!
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.