Return 404 Not Found in Rails

How to Return 404 Not Found Error in Rails

In this post, we'll learn about the HTTP 404 Not Found error: what it is and how it works, how to return a 404 response from a Rails application with a custom error page, and understand the impact of 404 errors on the SEO for your website or web application.

5 min read

The other day, I wanted to display a helpful web page when some resource was missing in my Rails app, and realized that I don't really understand how 404 Not Found errors work, especially how to return them from Rails. After a few hours of deep diving into HTTP and Rails documentation, and reading up on Google's SEO guidelines, here's everything I learned about 404 Not Found and how you can work with them in Rails.

Let me know in the comments if I missed something important.

What is a 404 Not Found Error?

Every webpage is a file on a computer somewhere. For static websites, it's literally a file, but for dynamic web applications, it's a file that the server program (Rails / Laravel, etc.) generates on the fly. If you try to go to a webpage that doesn't exist you get a 404 Not Found error.

The HTTP 404 Not Found status code indicates that the web application couldn't find a file or resource on the server.

The visitors to your application may run into a 404 Not Found page or error for different reasons:

  • A typo in the URL or a wrong URL
  • Broken or truncated links from an email message or a website
  • Deleted content or moved page to some other URL
💡
A 404 status code means that the resource is missing: not if the missing status is temporary or permanent. If the requested resource is moved permanently and you don't want to use the current URL, use the 410 (Gone) status instead. Otherwise, use 301 permanent redirect.

When the users see a 404 page, they will try to to fix the URL, click the browser's back button, or even navigate away from your site. If you want them to stay and go to the correct URL, you can display a custom 404 page to be more helpful to a user and provide guidance on what to do next.

For example, in addition to explaining that you couldn't find the requested page, you can provide the following information:

  • a link to the parent subdirectory
  • a web page containing the sitemap of your website
  • site search query suggestions and search box

In the end, your goal is to help the visitors find what they were looking for.

How to Return 404 Not Found Error in Rails

First, let's take a look at the more manual and explicit solution.

Out of the box, a 404.html file is provided in the public directory that you can customize. This view will be rendered for all 404 errors generated by your application.

To return 404 responses with the above view manually, in your ApplicationController class, add the following not_found! method:

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def not_found!
    render file: "#{Rails.root}/public/404.html", layout: false, status: :not_found
  end
end

The :not_found symbol corresponds to 404 status code.

Use the not_found! method from your controller actions as follows:

# app/controllers/posts_controller.rb

class PostsController < ApplicationController
  def publish
    Post.find_by_title(params[:title]) or not_found!
  end
end

However, most of the time you don't need to do this. Rails has this functionality built-in already.

The Rails Way

The good news is, you often don't have to do anything to render 404 pages in Rails. Rails will send the public/404.html file along with 404 Not Found error whenever one of the following exceptions occur in production.

  • ActionController::RoutingError
  • AbstractController::ActionNotFound
  • ActiveRecord::RecordNotFound

Or, if you want to return the 404 error explicitly, simply raise one of these exceptions.

class ApplicationController < ActionController::Base
  def not_found!
    raise ActionController::RoutingError.new("Not Found")
  end
end

It uses Rails' build-in rescue_from handler to render the 404 page. It also halts the execution of your code, which means the publish! method won't be executed.

def publish_post
  post = User.find_by_title(params[:title]) or not_found!
  post.publish!
end

What's more, the find method raises ActiveRecord::RecordNotFound error out of box, which returns a 404 response as shown below.

@post = Post.find(params[:id])
404 Not Found in Development (Rails)
404 Not Found in Development (Rails)

Note that you'll only be shown the detailed error message including the stack trace in development. In production, the users will be greeted with the following UI:

404 Not Found in Production (Rails)
404 Not Found in Production (Rails)

Alternatively, the bang versions of find_by methods raise an error automatically, so you don't even have to call the not_found method above.

def show
  user = User.find_by_email!(params[:email])
  # ...
end
💡
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called first_name on your Customer model for example, you get the instance method find_by_first_name for free from Active Record. If you also have a locked field on the Customer model, you also get find_by_locked method.

Do 404 Errors Hurt Your Website's SEO?

No. Missing resources are a perfectly normal part of the life on web. Websites on the Internet are always changing, new pages are born, old pages die, and when they die, ideally they are supposed to return a 404 HTTP response code. Hence 404 Not Found errors are fine. They won't negatively impact your website or app.

Google actually prefers that when you remove a page from your site, you ensure that it returns a proper 404 or 410 error code.

💡
Google won't process and index new URLs that return a 404 status code. In addition, it will remove all URLs that were already indexed but are now returning a 404 error from the index. Finally, the crawling and indexing frequency gradually decreases.

Should You Return 404 or 301?

HTTP 301 status means the web page has moved permanently.

When you remove a page from your site, think if the content on that page is moving somewhere else, or whether you don't plan to have that content on your site anymore.

If you're moving that content to a new URL, you should 301 redirect the old URL to the new URL - that way when users come to the old URL looking for that content, they'll be automatically redirected to the new URL.

For example, when I moved my blog from akshaykhot.com to writesoftwarewell.com, none of the URLs for any of my posts were changed. So when one visits akshaykhot.com/rails-database-migrations-cheatsheet, I use a 301 Moved Permanently status to redirect them to writesoftwarewell.com/rails-database-migrations-cheatsheet.

Yes, I do have a Caddy server sitting on a $4 instance on Digital Ocean whose sole job is to permanently redirect all requests on my old domain to the new one.

If you're getting rid of that content entirely and don't have anything on your site that would fill the same user need, then the old URL should return a 404 or 410.


That's a wrap. I hope you found this article helpful and you learned something new.

As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I reply to all emails I get from developers, and I look forward to hearing from you.

If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you.