how to handle ActiveRecord::RecordNotFound in rail

2020-05-23 09:46发布

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?

3条回答
ゆ 、 Hurt°
2楼-- · 2020-05-23 10:26

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
查看更多
一夜七次
3楼-- · 2020-05-23 10:45

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: ""
查看更多
够拽才男人
4楼-- · 2020-05-23 10:53

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.

查看更多
登录 后发表回答