在Rails 3中捕获自定义404的未知操作

我想在Rails 3中捕获未知的操作错误,该错误显示开发时的“未知操作”错误以及生产中的404.html。 我尝试将这个rescue_from处理程序放在我的ApplicationController上(以及实际的控制器,以防万一),但我仍然看到了丑陋的错误。

我在404上有自定义的东西,它不能是普通的.html文件。

我的路线:

 match '/user/:id/:action', controller: 'users' 

我正在访问的URL: /user/elado/xxx

rescue_from代码:

 rescue_from AbstractController::ActionNotFound, :with => :action_not_found def action_not_found render text: "action_not_found" end 

浏览器中的错误:

 Unknown action The action 'xxx' could not be found for UsersController 

在控制台中:

 Started GET "/user/elado/xxx" for 127.0.0.1 at 2011-09-07 19:16:27 -0700 AbstractController::ActionNotFound (The action 'xxx' could not be found for UsersController): 

尝试了rescue_from ActionController::UnknownAction

有什么建议? 谢谢!

当Rails 3出现时,rescue_from略有破坏(3.1中仍然被破坏)。 基本上你不能:

 rescue_from ActionController::RoutingError 

了。 看到这里 。

目前,解决方案是hamiltop推荐的解决方案。 使用捕获到“路由错误”路由的所有路由。 确保将它放在config \ routes.rb文件的末尾,以便最后处理它。

 # Any routes that aren't defined above here go to the 404 match "*a", :to => "application#routing_error" def routing_error render "404", :status => 404 end 

注意:此方法有一个主要缺点。 如果你使用像Jammit或Devise这样的引擎,那么所有路由都将使Rails忽略引擎的路由。

如果您没有使用拥有自己路线的发动机,那么您应该没问题。 但是,如果您使用定义其自己路线的引擎,请参阅@ arikfr的答案。

使用catch所有路径来处理404错误(正如@Seth Jackson建议的那样)有一个主要缺点:如果你使用定义自己路由的任何Rails引擎(例如Jammit),它们的路由将被忽略。

更好,更兼容的解决方案是使用可以捕获404错误的Rack中间件。 在我的一个项目中,我实现了将这些错误报告给Hoptoad的Rack中间件。 我的实现基于这个: https : //github.com/vidibus/vidibus-routing_error ,但我没有再次调用我的Rails应用程序来处理404错误,而是在Rack中间件中执行此操作并让nginx显示404页面。

如果你真的想要在控制器中解救AbstractController::ActionNotFound ,你可以尝试这样的事情:

 class UsersController < ApplicationController private def process(action, *args) super rescue AbstractController::ActionNotFound respond_to do |format| format.html { render :404, status: :not_found } format.all { render nothing: true, status: :not_found } end end public # actions must not be private end 

这将覆盖AbstractController::Baseprocess方法,该方法引发AbstractController::ActionNotFound (请参阅source )。

你有没有试过捕捉所有路线?

http://railscasts.com/episodes/46-catch-all-route

您当前使用的通配符路由是错误的想法(tm)。

我建议定义你关心的路由,然后做一个catchall作为routes.rb的最后一行(在routes.rb中首先定义的路由,以后定义)。 然后,您可以呈现所需的任何页面(并指定404状态代码)。

编辑:如果你真的想使用你当前的方法…(虽然这似乎可以被弃用)

def rescue_action(exception)caseexception当ActionNotFound,UnknownAction然后#处理这些exception在这里别的超级结束