Jensky
Jensky

Reputation: 917

How to handle error when ID is not found?

What is the best way to handle the error then ID is not found? I have this code in my controller:

  def show
    @match = Match.find(params[:id])
  end

I was thinking about something like this:

  def show
    if @match = Match.find(params[:id])
    else
      render 'error'
    end
  end

But I still get:

ActiveRecord::RecordNotFound in MatchesController#show

Couldn't findMatch with 'id'=2

Why?

What is the correct solution?

Upvotes: 15

Views: 12132

Answers (4)

Felix
Felix

Reputation: 4716

There is two approaches missing:

One is to use a Null-Object (there I leave research up to you)

Te other one was mentioned, but can be placed more reusable and in a way more elegantly (but it is a bit hidden from you action code because it works on a somewhat higher level and hides stuff):

class MyScope::MatchController < ApplicationController
  before_action :set_match, only: [:show]

  def show
    # will only render if params[:id] is there and resolves
    # to a match that will then be available in @match.
  end

  private

  def set_match
    @match = Match.find_by(id: params[:id])
    if [email protected]?
      # Handle somehow, i.e. with a redirect
      redirect_to :back, alert: t('.match_not_found')
    end
  end
end

Upvotes: 0

Faizan
Faizan

Reputation: 383

You can use find_by_id method it returns nil instead of throwing exception

    Model.find_by_id

Upvotes: 1

xdazz
xdazz

Reputation: 160873

Rescue it in the base controller and leave your action code as simple as possible. You don't want to deal not found exception in every action, do you?

class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, :with => :render_404

  def render_404
    render :template => "errors/error_404", :status => 404
  end
end

Upvotes: 36

Francesco Boffa
Francesco Boffa

Reputation: 1402

By default the find method raises an ActiveRecord::RecordNotFound exception. The correct way of handling a not found record is:

def show
  @match = Match.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
  render 'error'
end

However, if you prefer an if/else approach, you can use the find_by_id method that will return nil:

def show
  @match = Match.find_by_id(params[:id])
  if @match.nil?     # or unless @match
    render 'error'
  end
end

Upvotes: 7

Related Questions