【问题标题】:how to handle ActiveRecord::RecordNotFound in rails controller?如何处理 Rails 控制器中的 ActiveRecord::RecordNotFound?
【发布时间】:2012-10-01 21:39:37
【问题描述】:

我有一个包含用户和事件的应用。每个用户都有几个事件。当用户想要查看特定事件时,他会执行此操作:

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 

解决此问题的最佳方法是什么?

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    在重定向后放 return

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

    【讨论】:

      【解决方案2】:

      调用redirect_to 不会从您的操作方法中返回,这就是为什么转到respond_to 块会导致DoubleRenderError。解决此问题的一种方法是:

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

      但是,更好的解决方案可能是声明性地处理rescue from 这个异常,或者让它传播到客户端。前者看起来像这样:

      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 页面。

      【讨论】:

      • 不明白您的解决方案...为什么每次都在控制器中进行救援?...我需要它只是在表演动作中。不过谢谢
      • rescue_from 有时只是处理常见错误的一种更好的方法,允许您在代码中分离出关注点。当然它并不总是更好,因此其他两个选项:-)
      【解决方案3】:

      在应用控制器中,请写:

          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 文件夹根目录中。
      猜你喜欢
      • 2015-12-21
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 2018-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多