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

时间:2011-09-08 03:34:51

标签: ruby-on-rails ruby-on-rails-3 http-status-code-404

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

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

我的路线:

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

我正在访问的网址:/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

有什么建议吗? 谢谢!

4 个答案:

答案 0 :(得分:14)

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

rescue_from ActionController::RoutingError

了。请参阅here

目前,解决方案是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的答案。

答案 1 :(得分:9)

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

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

答案 2 :(得分:2)

如果您真的想在控制器中解救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

这会覆盖引发process的{​​{1}} AbstractController::Base方法(请参阅source)。

答案 3 :(得分:0)

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

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

您当前使用的通配符路由是一个坏主意(tm)。

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

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

def rescue_action(例外)       案例例外       当ActionNotFound,然后是UnknownAction         #在这里处理这些例外       其他         超       结束 端