Don't render 404 yourself, there's no reason to; Rails has this functionality built in already. If you want to show a 404 page, create a render_404 method (or not_found as I called it) in ApplicationController like this:

def not_found
  raise ActionController::RoutingError.new('Not Found')
end

Rails also handles AbstractController::ActionNotFound, and ActiveRecord::RecordNotFound the same way.

This does two things better:

1) It uses Rails' built in rescue_from handler to render the 404 page, and 2) it interrupts the execution of your code, letting you do nice things like:

  user = User.find_by_email(params[:email]) or not_found
  user.do_something!

without having to write ugly conditional statements.

As a bonus, it's also super easy to handle in tests. For example, in an rspec integration test:

# RSpec 1

lambda {
  visit '/something/you/want/to/404'
}.should raise_error(ActionController::RoutingError)

# RSpec 2+

expect {
  get '/something/you/want/to/404'
}.to raise_error(ActionController::RoutingError)

And minitest:

assert_raises(ActionController::RoutingError) do 
  get '/something/you/want/to/404'
end

OR refer more info from Rails render 404 not found from a controller action


HTTP 404 Status

To return a 404 header, just use the :status option for the render method.

def action
  # here the code

  render :status => 404
end

If you want to render the standard 404 page you can extract the feature in a method.

def render_404
  respond_to do |format|
    format.html { render :file => "#{Rails.root}/public/404", :layout => false, :status => :not_found }
    format.xml  { head :not_found }
    format.any  { head :not_found }
  end
end

and call it in your action

def action
  # here the code

  render_404
end

If you want the action to render the error page and stop, simply use a return statement.

def action
  render_404 and return if params[:something].blank?

  # here the code that will never be executed
end

ActiveRecord and HTTP 404

Also remember that Rails rescues some ActiveRecord errors, such as the ActiveRecord::RecordNotFound displaying the 404 error page.

It means you don't need to rescue this action yourself

def show
  user = User.find(params[:id])
end

User.find raises an ActiveRecord::RecordNotFound when the user doesn't exist. This is a very powerful feature. Look at the following code

def show
  user = User.find_by_email(params[:email]) or raise("not found")
  # ...
end

You can simplify it by delegating to Rails the check. Simply use the bang version.

def show
  user = User.find_by_email!(params[:email])
  # ...
end