2012-11-17 115 views
14

我偶然发现我的应用程序查找数据库中不存在的id的情况。抛出异常。当然,对于任何Web开发人员来说,这都是相当标准的情况。通用救援整个控制器时,没有找到id - RoR

感谢this answer我知道,使用救援涉及的情况非常整齐,像这样:

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,它应当重定向到索引页面(或,一般来说,执行一个特定的任务)?

回答

31

必须使用rescue_from这项任务。看到Action Controller Overview Guide

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

    private 

    def record_not_found 
    redirect_to action: :index 
    end 
end 
+1

太棒了,就是这样做,谢谢!出于好奇:为什么这种方法应该是私人的? – weltschmerz

+1

只是为了清洁:该方法不需要对其他控制器可见,这就是为什么它被宣布为私有。如果该方法未被声明为私有,它将同样工作。 – Baldrick

+2

您还可以添加一个flash讯息 flash [:notice] =“没有找到记录” –

8

Rails已经内置rescue_from类方法:

class CustomersController < ApplicationController 
    rescue_from ActiveRecord::RecordNotFound, with: :index 
    ... 
end 
+0

这看起来很优雅。我试了一下,但它留下了浏览器中的空白页面,并且在url中仍然显示“customers /:id”。我错过了什么吗?在我看来,它试图呈现索引而不是重定向到它。 – weltschmerz

+0

你是对的..尝试类似Baldrick在下面提出的建议(即使用重定向的中间方法)。 –

1

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

只要确保检查nils以避免NoMethodError

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

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 
+0

“全球”一词引起了我的注意。有没有办法在所有控制器中执行此操作?这将非常有帮助。 – weltschmerz

+1

我认为要以全局的方式来描述我所描述的可能需要一些元编程。但是为了简单地拯救全局的ActiveRecord :: RecordNotFound,你可以在你的ApplicationController中使用rescue_from。 – bratsche