🚧 Under Construction! Full version coming soon! 🚧

Rails Maze

5 Common Rails Errors (And How to Solve Them)

5 Common Rails Errors (And How to Solve Them)

Published on

To us programmers, errors are a way of life. We work hard to make sure they don't happen, design them so they provide useful information, wrestle with them until the wee hours of the morning, and (with enough experience) learn to appreciate them.

That doesn't make dealing with them any less frustrating, however. Let's dive into some common Rails errors and explore not only how to fix them, but why they are being raised in the first place.

How to Fix ActionController::RoutingError

  1. Check that you have the correct route defined in config/routes.rb. You may have missed the definition!
  2. You may have the wrong HTTP verb coming from the client.
    • Look in your console for a log like Started GET "/things" for ::1 at 2025-05-06 22:46:18 -0700. This will let you know exactly what verb is being used.
  3. Check your path and URL helpers. You may want to run rails routes and check the prefix column for the name of the base route helper methods.
  4. If you are seeing this when trying to serve images or static assets, ensure that you are using the correct asset helper.
    • image_tag('logo.png') — Generates an <img> HTML tag for an image asset.
    • image_path('logo.png') — Returns the URL path to an image asset, without generating an HTML tag.
    • asset_path('logo.png') — General method for any asset (not just images), returning the relative path.
    • asset_url('logo.png') — Returns the full absolute URL to the asset (including host if configured).
  5. If you are stuck, or need a fallback option, there is a way to add a 'catch all' route to handle failures more gracefully. ⚠️ Make sure this route is defined at the very bottom of your config/routes.rb file so it doesn’t interfere with valid routes. ⚠️

    match '*path', to: 'application#not_found', via: :all
    

What is the purpose of ActionController::RoutingError?

ActionController::RoutingError is Rails' way of making sure every request coming into your app has a place to go, and that place has to be explicitly defined. It’s there to protect your app from bots poking around where they shouldn't be, to make sure you’re only exposing what you actually intend to, and to stick to Rails' philosophy of convention over configuration. It keeps your app predictable, secure, and a whole lot easier to maintain as it grows.

Rails Maze Logo Divider

How to Fix NoMethodError: undefined method '[]' for nil:NilClass

  1. If you are calling this on a Hash, you are probably trying to access a key that doesn't exist. This commonly happens when trying to access nested keys in params. Try using #dig to safely access nested hashes!

    params = {}
    admin = params[:admin][:name]
    #=> NoMethodError: undefined method '[]' for nil:NilClass
    
    params = { admin: { name: "Shrek" } }
    admin = params.dig(:admin, :name)
    #=> "Shrek"
    
  2. You may be trying to call the #[] method on an object that doesn't have it defined. This commonly happens with nil. You can use the Safe Navigation Operator (&.) to safely call methods even when an object might be nil.

  3. You may have a nil value! Try to be defensive and ensure that things are not nil.

    if admin.present?
        greeting = "Hello, #{admin.name}!"
    else
        greeting = "Hello, guest!"
    end
    
    # Or with a strong default...
    
    greeting = "Hello, #{admin&.name || 'Shrek'}!"
    
  4. Whenever you hit a NoMethodError involving nil, it’s a signal to double-check your assumptions about your data and not just patch the crash.

What is the purpose of NoMethodError: undefined method '[]' for nil:NilClass?

NoMethodError: undefined method '[]' for nil:NilClass is how Rails tells you that there is no method (#[] in this case) on the object you are trying to invoke it on. This is part of Ruby’s fail fast philosophy: it surfaces problems right away, instead of letting bugs hide and cause weird behavior later.

Rails Maze Logo Divider

How to Fix ActionController::InvalidAuthenticityToken

  1. Make sure that you include CSRF meta tags in your layout. This automatically sets the CSRF token that Rails uses to make PUT, POST and PATCH requests.

    <%= csrf_meta_tags %>
    
  2. Use Rails form helpers! They are both convenient and powerful. They will automagically add the CSRF token to the form.

    <%= form_with model: @post do |f| %>
        ...
    <% end %>
    
    # If you don't have a model for a form, you can always use:
    
    <%= form_tag '/some_path' do %>
        ...
    <% end %>
    
  3. If you are manually writing HTML forms, you can also add the CSRF token to it manually. Generally, it's advised not to do this as you miss out on a lot of important Rails magic!

    <form action="/some_path" method="post">
        <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
        ...
    </form>
    
  4. If you are making AJAX requests, you need to set the X-CSRF-Token header using the Rails-generated CSRF token. If you are using Rails UJS (Unobtrusive JS), Rails will set this automatically. If you are using your own (like jQuery, Fetch, or Axios) you will need to retrieve the value and set it:

    const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    
    fetch('/posts', {
        method: 'POST',
        headers: {
            'X-CSRF-Token': token,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ post: { title: "New Post" } })
    });
    
  5. There may be an expired session which can be from it expiring naturally, cookies being cleared, or it becoming corrupted. If you have narrowed it down to a session problem and are not being redirected automatically, it could be that they are not being redirected back to the login page correctly. Check your controllers and make sure that something hasn't been overridden or misconfigured.

What is the purpose of ActionController::InvalidAuthenticityToken?

If you see InvalidAuthenticityToken, it's not just a bug! It's Rails stepping in to protect you. It's a chance to double-check how you're building forms, handling sessions, or sending requests. Rails is trying to keep you and your users safe.

⚠️ In select cases you may want to skip CSRF authentication. Be really sure before skipping CSRF protection. If you do, it's your responsibility to lock the endpoint down another way. Valid use-cases could be a public API endpoint, Webhook endpoints, or internal services. ⚠️

class PublicFacingController < ApplicationController
  skip_before_action :verify_authenticity_token # Above other auth calls
  before_action :verify_api_key # Custom authentication

  def update
      Admin.update!(name: params.dig(:admin, :name))
  end
end
Rails Maze Logo Divider

How to Fix ActiveRecord::RecordNotFound

  1. Handle it gracefully! If you are working with controllers, you can use rescue_from to handle this behavior. This is very common when designing APIs, as you can :

    # Normal Rails controller with a 'show' view. 
    class AdminController < ApplicationController
        rescue_from ActiveRecord::RecordNotFound, with: :not_found
    
        def show
            @admin = Admin.find(params[:id])
        end
    
        private
    
        def not_found
            render file: Rails.root.join('public/404.html'), status: :not_found, layout: false
        end
    end
    
    # API Version where it's used as a 'catch' so the correct response can be given back.
    class ApplicationController < ActionController::Base
        rescue_from ActiveRecord::RecordNotFound, with: :render_not_found  
    
        private
    
        def render_not_found
            render json: { error: 'Not Found' }, status: :not_found
        end
    end
    
  2. Use a safe finder method! You may be using #find when it's OK if the record doesn't exist. You will want to use a method like #find_by instead.

    admin = Admin.find(42)
    # => ActiveRecord::RecordNotFound (Couldn't find Admin with 'id'=42)
    
    admin = Admin.find_by(id: 42)
    # => nil
    
    # Remember, find_by works with any attribute and will return the first matching record!
    admin = Admin.find_by(name: 'Shrek')
    # => #<Admin id: 7, name: "Shrek", email: "shrek@railsmaze.com", created_at: "2025-05-06 23:10:15", updated_at: "2025-05-06 23:10:15">
    
    

What is the purpose of ActiveRecord::RecordNotFound?

It's greatest strength is that it provides protection against bad assumptions. You don't want to accidentally authorize a nil record for an Admin! It also reduces subtle bugs due to nil assumptions. By raising an error immediately when something is missing, Rails forces you to handle edge cases intentionally, not leave them wide open to exploitation.

Rails Maze Logo Divider

How to Fix ActiveRecord::RecordNotUnique

  1. Validate for uniqueness on the model. This is useful as you can provide users with a meaningful feedback message instead of a generic error. You can enforce uniqueness like this:

    class Admin < ApplicationRecord
        validates :email, uniqueness: { case_sensitive: false }
    end
    
  2. Validate for uniqueness on the database. This can be considered mandatory in many cases for columns like emails, phone numbers, unique slugs, and sensitive payment information.

    class AddEmailToAdmins < ActiveRecord::Migration[8.0]
        def change
            # Add the email column first
            add_column :admins, :email, :string
    
            # Then add a unique index on the email column
            add_index :admins, :email, unique: true
        end
    end
    
  3. You can also rescue the error. This is particularly handy in API contexts.

    begin
        Admin.create!(email: params[:email])
    rescue ActiveRecord::RecordNotUnique
        render json: { error: "That email address is already taken." }, status: :unprocessable_entity
    end
    

What is the purpose of ActiveRecord::RecordNotUnique?

Rails tries to be nice to users. PostgreSQL protects your data when users (or your app) aren’t nice. Always validate uniqueness at the Rails level for a friendly experience. Always enforce it at the database level for true safety. Failing fast with RecordNotUnique prevents ghost users, duplicate purchases, impersonations, and billing errors.

Conclusion

Whether it's a missing route, a method call on nil, a missing database record, or a uniqueness violation, errors in Rails aren't just obstacles. They’re feedback loops, designed to help you catch problems early, protect your users, and keep your application stable as it grows.

  • Every RoutingError reminds you to be explicit about your app’s structure.
  • Every NoMethodError challenges you to handle missing data carefully.
  • Every RecordNotFound enforces the idea that you can't assume the world will always behave the way you want.
  • Every RecordNotUnique protects your data — and your business — from collapsing under concurrency.

Instead of fighting Rails when it raises these errors, it's better (and honestly more fun) to listen carefully to what it's trying to tell you.

Each failure is an opportunity to make your system stronger, clearer, and more resilient.

Treat your errors like mentors. They aren't the enemy — they're trying to make you a better developer.


Continue Learning