如何在Rails控制器中处理ActiveRecord :: RecordNotFound?

18

我的应用中有用户和事件。每个用户都有多个事件。当用户想查看特定的事件时,他将执行以下操作:

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
如果某个用户没有找到该事件,这意味着他在URL上进行了操作,而他尝试获取的事件不属于他。我想要将他重定向到主页或只显示一个错误页面,告诉他未找到该事件。如果我尝试运行上面的代码,将会触发此错误:
AbstractController::DoubleRenderError in EventsController#show 

有什么最好的方法来解决这个问题?

3个回答

25

在重定向之后加上return

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

18

调用redirect_to不会从您的操作方法中返回,这就是为什么继续执行respond_to块会导致DoubleRenderError。解决方法之一是:

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

然而,更好的解决方案可能是通过声明性地从中进行救援,或者直接将其传播到客户端。前者应该像这样:

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

如果你让异常一直存在,那么在生产模式下用户将会看到public/404.html页面。


我不太理解你的解决方案...为什么每次都要在控制器中进行救援操作?我只需要在展示操作中进行。但还是谢谢。 - guy schaller
rescue_from 只是在处理常见错误时更好的方式,允许您在代码中分离出关注点。当然,并不总是更好,因此还有其他两个选项 :-) - noodl

5
在应用程序控制器中,请编写以下内容:
    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

创建一个名为 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 %>

在en.yml文件中

en:
  errors:
    "404":
      description: "The page you are looking for does not exist!"
      heading: "Record not found"
      subheading: ""

快速提醒,error.htm.erb 应该放在 /views 文件夹的根目录下。 - Antonio Lopes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接