Ruby on Rails Debugging: Tools, Errors and Fixes

ruby on rails debugging

Your Rails app is misbehaving and the cause is not obvious. Good ruby on rails debugging starts with the log, view helpers and an interactive debugger, then adds monitoring for production.

Item Value
Log levels Six levels, numbered 0 to 5
Default log level :debug, but :info in production in the default generated config
Log file location Rails.root/log/, named after the environment
Logger class ActiveSupport::Logger
Built-in view inspection helpers Three: debug, to_yaml and inspect

These figures come from the Rails Guides chapter on debugging. Defaults can change between Rails versions, so check the source before you rely on them.

A repeatable Rails debugging workflow

Most Rails bugs feel mysterious because you are guessing instead of observing. The Rails Guides say their debugging chapter covers how to track down problems in your application that your tests aren’t identifying, and how to analyze the stack trace. Those are the two skills the rest of this page builds on.

A routine is only useful if you can follow it when you are tired and the site is down. This one is short on purpose:

  1. Reproduce the failure with the smallest request, record or console call you can.
  2. Read the stack trace from the top and find the line that points into your own code rather than into a gem or the framework.
  3. Form a single guess about which value is wrong, and name the line where you can look at it.
  4. Inspect that value with a view helper, a log line or a debugger.
  5. Fix the cause, then write a test that fails without the fix.
  6. Make sure the next occurrence reaches you through the log or a monitoring tool.

The stack trace is the cheapest clue you have. Each line names a file, a line number and a method. The top lines show where the error was raised, and the lines below show how the request got there.

Reproduction deserves the most care of all the steps. A bug you can trigger on demand is well on its way to being solved, because every later step becomes a quick experiment. Write down the exact input, the state of the user or record involved, and the route that triggers the failure.

If the failure depends on data, capture a small record that causes it instead of testing against a full copy of production. A minimal case also makes a better test later, and it shows you which attribute actually matters. Strip away everything that does not change the outcome.

When you cannot reproduce the failure, treat that as a finding. Ask what differs between the place where it fails and the place where it works: the data, the configuration, background jobs, timing, or the versions of your gems. List the differences and remove them one by one until the failure appears or disappears.

Good guesses are specific and testable. Compare these examples with a vague hunch such as “something is wrong with the model”:

  • “This user has no profile record, so the method is called on nil.” You can test that by loading the record in a console.
  • “The query runs before the filter sets the value.” You can test that by comparing the order of the log lines.
  • “Production uses a different setting from development.” You can test that by comparing the environment files side by side.
ruby on rails debugging Laptop keyboard
A silver laptop with a dark screen rests on a pale surface.

Resist the urge to change code before you have seen the bad value. Edits made on a hunch often hide the symptom while the cause stays in place, and you lose the one failing case you had. If you want the general habits behind this routine, our overview of debugging techniques goes through them in a language-neutral way.

Change only a single variable at a time while you test a guess. If you alter the code, the data and the configuration together, a fix that appears to work teaches you nothing about why. Keep brief notes as you go, listing what you tried and what you saw, so you do not repeat a dead end an hour later.

Version control is a useful ally here. If the bug is new, look at the recent changes and ask which of them touches the failing path. Reverting a suspect change locally, then restoring it, is a fast way to confirm or rule it out.

Know when to ask for help, and prepare before you do. Write the problem down in plain words: what you expected, what happened, and what you have already ruled out. Explaining it clearly often reveals the gap on its own, and if it does not, a colleague or forum reader now has what they need to help you.

Finally, close the loop with a regression test. The test proves the fix works, protects the next refactor, and records the failing case for anyone who reads the code later. A bug fixed without a test is a bug you may meet again.

Inspect values in views and logs

Before you reach for a debugger, see what the app can already tell you. Rails ships with helpers for views and a logger for everything else. Both are cheap, and both work without stopping the request.

View helpers for quick inspection

The Rails Guides say that Rails provides three built-in ways to inspect the contents of a variable from a view:

  • debug returns a pre tag that renders the object using the YAML format, which gives you human-readable data from any object.
  • to_yaml converts any object to YAML. You can pass the result into the simple_format helper to format the output, and the guide notes this is how debug does its magic.
  • inspect prints the object value as a string, and is especially handy for arrays and hashes.

Use these while you work in development and remove them before you ship. A raw object dump on a public page can leak data that users were never meant to see. If you need to keep the output, send it to the log instead.

The Rails logger

According to the Rails Guides, Rails makes use of the ActiveSupport::Logger class to write log information, and other loggers such as Log4r may be substituted. That means you can keep the standard logger or swap in your own without changing the calls in your code.

Rails keeps a separate log file for each runtime environment. By default, each log is created under Rails.root/log/ and the file is named after the environment in which the application is running. When you debug a development problem, that is the file to watch while you reproduce it.

The logger works with six levels, numbered 0 up to 5 in the guide. Their order matters because it controls what gets written:

  • debug is number 0.
  • info is number 1.
  • warn is number 2.
  • error is number 3.
  • fatal is number 4.
  • unknown is number 5.

A message is printed into the corresponding log only if its level is equal to or higher than the configured log level, as the guide explains. Our separate page on rails logger levels covers how to pick the right level for each message.

The default level needs a careful read. In the current guide, the default Rails log level is :debug, but it is set to :info for the production environment in the default generated config/environments/production.rb. An older edition of the guide says the default is debug in all environments, so look at your own app’s configuration rather than assuming.

To see the level your app uses right now, call the Rails.logger.level method from a console. To change it, set config.log_level to :warn in config/environments/production.rb, as in the current guide. The guide says this is useful when you want to log under development or staging without flooding your production log with unnecessary information.

ruby on rails debugging Illuminated laptop
An open laptop is lit by pink and blue light against a dark background.

The guide’s logger section goes further than levels. Its chapter list includes verbose query logs, verbose enqueue logs, verbose redirect logs, SQL query comments, tagged logging and the impact of logs on performance. Read that list as a reminder that logging has a cost as well as a benefit, so turn up detail where you need it and turn it back down afterwards.

A few habits make log lines far more useful when you are chasing a bug:

  • Log the value you are suspicious of, and say which variable it is, so the line makes sense later.
  • Put one message before and one after the risky call, so you can see whether the code reached it and returned.
  • Pick a level on purpose: detail for debug, expected events for info, and real problems for error.
  • Take temporary debug lines out once the bug is fixed, or lower them to a level that stays quiet in production.

Step through code with the debug gem and web-console

Logs tell you what happened after the fact. A debugger pauses the request in the middle so you can look around. The Rails Guides release list tops out at Version 8.1 – October 2025, and the current debugging chapter has a section titled “Debugging with the debug Gem” that covers entering a debugging session, the context and breakpoints.

An older edition of the guide covered the byebug gem instead, with sections on setup, the shell, the context and threads. If your project still uses the older tool, the walkthrough to debug rails with byebug explains how it works.

The current guide also gives the web-console gem its own chapter, with sections on the console, inspecting variables and settings. It is a different style of tool from a terminal debugger, so read that chapter before you decide which one fits your workflow.

Each tool answers a different question, so pick by the question you have:

  • You want a quick look at one object while a page renders: use a view helper such as debug or inspect.
  • You want to know which path a request took, or which query ran: read the log.
  • You need to explore the live state of a running request: use the debug gem or web-console in development.
  • You cannot reproduce the bug on your machine: rely on production logs and error reports.

A debugger is a question-asking tool, so decide the question before you pause. Write down which value you expect and which you suspect, then check just that. Do not commit breakpoints to your repository, because a paused process in a shared environment helps nobody.

ruby on rails debugging Dark screen
A close-up of a dark computer screen shows faint multicolored lines.

Common Rails errors and the guides that fix them

Many of the failures you meet in a Rails app fall into a small set of families. Each family below links to a focused page, so you can move from symptom to cause without reading everything here.

  • A page that blows up because something you expected to exist is missing is the classic case of undefined method for nil rails, and that page shows how to trace the missing value back to where it should have been set.
  • A page that works but feels slow is often doing far too many database calls, which is the pattern explained in rails n+1 queries.
  • A blank error page for users, with a stack trace only in your logs, is the situation covered in rails 500 internal server error.
  • Deciding where errors should be caught and what happens next is the subject of rails exception handling.
  • Handling the same exception once for a whole controller, rather than in every action, is what rails rescue_from is for.
  • Showing users something helpful when things go wrong is the job of rails custom error pages.

These topics fit together. An exception is raised, handled or not, logged, and then shown to the user in some form. When you debug, follow that chain in order and ask at each step whether the information you need survived.

Handling an error and fixing it are different jobs. A rescue block that swallows an exception can keep a page alive while the real fault goes on causing damage. Whenever you rescue an error, log it with enough detail that you can still find the cause later.

Debugging production: errors, logs and memory

Production hides details from users, and rightly so, which means you depend on logs and reports to see what went wrong. A dedicated error monitoring setup collects exceptions with their context, so you hear about a failure from a tool instead of from a customer. Our page on error monitoring explains what to look for in that kind of setup.

The Rails Guides index also lists a guide titled “Error Reporting in Rails Applications”, which is worth reading alongside the debugging chapter when you plan how your app reports errors. It sits in the same part of the index as the performance and security guides.

Logging in production needs a balance. As covered above, the generated production config uses :info rather than :debug, and the guide has a section on the impact of logs on performance. Raise the level for a short, targeted investigation and then put it back, so the log stays readable and cheap.

Some bugs are not exceptions at all. A process that slowly uses more and more memory needs a different approach, and the guide has a chapter on debugging memory leaks with sections on Valgrind and on how to find a memory leak. It also ends with a section on plugins for debugging, which is a useful place to look when the built-in tools run out.

When an incident is live, a short checklist keeps you calm:

  1. Note the time, the URL and the exact error message.
  2. Find the matching entries in the production log at the error level.
  3. Reproduce the failure locally with data that matches the failing case.
  4. Fix the cause and add a test that covers it.
  5. Deploy, then watch the log or monitor to confirm the error has stopped.

Afterwards, ask why you did not know sooner. If a user reported it first, add the logging or alerting that would have told you. That habit turns every incident into better visibility for the next one.

Frequently asked questions

What is the default Rails log level?

Show answer

In the current Rails Guides chapter, the default is :debug, but it is set to :info for the production environment in the default generated config/environments/production.rb. An older edition of the guide describes debug in all environments, so confirm the value in your own app.

How do I change the log level?

Show answer

Set config.log_level to the level you want, for example :warn, in the environment file such as config/environments/production.rb, as shown in the Rails Guides. You can check the active level by calling Rails.logger.level.

How do I inspect an object inside a view?

Show answer

Use the debug helper, which renders the object as YAML inside a pre tag. You can also call to_yaml and pass it to simple_format, or call inspect for arrays and hashes. Remove these before you deploy.

Should I use byebug or the debug gem?

Show answer

The current guide has a chapter on the debug gem, while an older edition covered byebug. Choose the one your Rails version and project already use, and read the matching edition of the guide.