15

我偶然发现了我的应用程序查找数据库中不存在的 id 的情况。抛出异常。当然,对于任何 Web 开发人员来说,这都是相当标准的情况。

多亏了这个答案,我知道使用救援可以很好地处理这种情况,如下所示:

def show
  @customer = Customer.find(params[:id])
  rescue ActiveRecord::RecordNotFound #customer with that id cannot be found
    redirect_to action: :index        #redirect to index page takes place instead of crashing
end

如果找不到客户,则将用户重定向到索引页面。这绝对没问题。

现在,这一切都很好,但我需要在显示、编辑、销毁等操作中进行相同的救援尝试,即每个需要特定 ID 的控制器方法。

话虽如此,这是我的问题: 有没有办法通常告诉我的控制器,如果它在任何方法中都找不到 id,它应该重定向到索引页面(或者,通常,执行特定任务)?

4

4 回答 4

34

您必须rescue_from用于此任务。请参阅动作控制器概述指南中的示例

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

  private

  def record_not_found
    redirect_to action: :index
  end
end
于 2012-11-17T20:38:48.213 回答
8

Rails 有一个内置的rescue_from类方法:

class CustomersController < ApplicationController
  rescue_from ActiveRecord::RecordNotFound, with: :index
  ...
end
于 2012-11-17T20:38:05.977 回答
3

如果您要在单个控制器中执行此操作(而不是在每个控制器中全局执行此操作),那么这里有几个选项:

您可以使用 before_filter 来设置您的资源:

class CustomerController < ApplicationController
  before_filter :get_customer, :only => [ :show, :update, :delete ]

  def show
  end

  private

  def get_customer
    @customer = ActiveRecord.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      redirect_to :action => :index
  end
end

或者您可以改用一种方法。我一直在朝着这个方向前进,而不是在视图中使用实例变量,它也可以帮助您解决问题:

class CustomerController < ApplicationController
  def show
    # Uses customer instead of @customer
  end

  private

  def customer
    @customer ||= Customer.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      redirect_to :action => :index
  end
  helper_method :customer
end
于 2012-11-17T20:45:42.040 回答
1

在某些情况下,我建议您使用Model.find_by_id(id)而不是Model.find(id). 不是抛出异常,而是.find_by_id返回nil。如果找不到记录。

只要确保检查 nils 以避免NoMethodError

PS 对于它的价值,Model.find_by_id(id)在功能上等同于Model.where(id: id),如果你愿意,它可以让你建立一些额外的关系。

于 2012-11-17T20:44:35.477 回答