Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to handle ActiveRecord::RecordNotFound in rails controller?

I have an app with user and events. Each user has several events. When a user wants to see a specific event he will get to this action:

def show
  begin
    @userEvents = current_user.event
    @event = @userEvents.find(params[:id])
  rescue ActiveRecord::RecordNotFound  
    redirect_to :controller => "main", :action => "index"
  end

  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @event }
  end
end

If the event is not found for the user it means he played with the URL and the event he is trying to get does not belong to him. I want to either redirect him to the main page or just display the page with an error that the event is not found. If I try to run the code above this error fires:

AbstractController::DoubleRenderError in EventsController#show 

What's the best way to fix this?

like image 661
guy schaller Avatar asked Oct 01 '12 21:10

guy schaller


3 Answers

Put return after redirect

begin
 @userEvents = current_user.event
 @event = @userEvents.find(params[:id])
rescue ActiveRecord::RecordNotFound  
 redirect_to :controller => "main", :action => "index"
 return
end
like image 142
Walt Avatar answered Oct 21 '22 14:10

Walt


Calling redirect_to doesn't return from your action method which is why moving on to the respond_to block causes the DoubleRenderError. One way to fix that is with:

redirect_to :controller => "main", :action => "index" and return

However, a better solution might be to either rescue from this exception declaratively or just let it propagate to the client. The former look like this:

class YourController < ActionController::Base

  rescue_from ActiveRecord::RecordNotFound, with: :dude_wheres_my_record

  def show
    # your original code without the begin and rescue
  end

  def dude_where_my_record
    # special handling here
  end
end

If you just let the exception fester the user will see the public/404.html page in production mode.

like image 38
noodl Avatar answered Oct 21 '22 13:10

noodl


In application controller, please write:

    rescue_from (ActiveRecord::RecordNotFound) { |exception| handle_exception(exception, 404) }

   protected

    def handle_exception(ex, status)
        render_error(ex, status)
        logger.error ex   
    end

    def render_error(ex, status)
        @status_code = status
        respond_to do |format|
          format.html { render :template => "error", :status => status }
          format.all { render :nothing => true, :status => status }
       end
    end

Create a page error.html.erb

<div class="page-header">
  <h1>
    <%= t "errors.#{@status_code}.heading" %>
    <small><%= t "errors.#{@status_code}.subheading" %></small>
  </h1>
</div>
<p><%= t "errors.#{@status_code}.description" %></p>
<% if defined? root_path %>
  <%= link_to t(:return_to_home), root_path %>
<% end %>

and in en.yml

en:
  errors:
    "404":
      description: "The page you are looking for does not exist!"
      heading: "Record not found"
      subheading: ""
like image 43
Vijay Chouhan Avatar answered Oct 21 '22 13:10

Vijay Chouhan