在Rails 4中,处理ActionController路由错误的救援方案

26

我遇到了以下错误:

ActionController::RoutingError (No route matches [GET] "/images/favicon.ico")

我想为不存在的链接显示错误404页面。

我该如何实现这一点?

4个回答

62
application_controller.rb中添加以下内容:
  # You want to get exceptions in development, but not in production.
  unless Rails.application.config.consider_all_requests_local
    rescue_from ActionController::RoutingError, with: -> { render_404  }
  end

  def render_404
    respond_to do |format|
      format.html { render template: 'errors/not_found', status: 404 }
      format.all { render nothing: true, status: 404 }
    end
  end

我通常也会处理以下异常,但这取决于你:

rescue_from ActionController::UnknownController, with: -> { render_404  }
rescue_from ActiveRecord::RecordNotFound,        with: -> { render_404  }

创建错误控制器:
class ErrorsController < ApplicationController
  def error_404
    render 'errors/not_found'
  end
end

然后在routes.rb文件中

  unless Rails.application.config.consider_all_requests_local
    # having created corresponding controller and action
    get '*path', to: 'errors#error_404', via: :all
  end

最后一件事是在 /views/errors/ 下创建 not_found.html.haml(或您使用的任何模板引擎):
  %span 404
  %br
  Page Not Found

11
这在Rails 4.2.5中不起作用。我猜这是因为ActionDispatch在运行任何控制器代码之前就抛出了异常。 - depquid
@depquid 我是在 Rails 4.0.x 时代编写它的,但现在我刚测试了一下 Rails 4.2.5 - 我猜你可能没有添加路由并且没有创建 errors_controller.rb :) 如果是这种情况的话 - 请确保收回你的反对投票,除非你有更多原因让它保留。 - Andrey Deineko
7
抱歉,我没有正确设置路由。但是,如果你直接路由到操作,为什么要使用 rescue_from ActionController::RoutingError, with: -> { render_404 } 呢? - depquid
如果您需要在任何控制器代码运行之前捕获此问题(即在路由层面上),请参见@misu的答案,添加match '*path' => 'errors#error_404', via::all - skplunkerin
1
当你有一个匹配所有路径的路由(get '*path', to: 'errors#error_404', via: :all)时,如何出现 ActionController::RoutingError 错误? - B Seven

10

@Andrey Deineko,你的解答似乎仅适用于控制器内手动引发的RoutingError。如果我使用URL my_app/not_existing_path尝试它,我仍然会得到标准错误消息。

我猜这是因为应用程序甚至没有到达控制器,因为Rails在之前就引发了错误。

解决问题的窍门是在路由的末尾添加以下行:

Rails.application.routes.draw do
  # existing paths
  match '*path' => 'errors#error_404', via: :all
end

捕获所有未预定义的请求。

然后在ErrorsController中,您可以使用respond_to来处理html、json等请求:

class ErrorsController < ApplicationController
  def error_404
    @requested_path = request.path
    repond_to do |format|
      format.html
      format.json { render json: {routing_error: @requested_path} }
    end
  end
end

你能解释一下 @requested_path = request.path 以及对应的调用 format.json { render json: {routing_error: @requested_path} } 吗? - Afolabi Olaoluwa
我刚在模板(error_404.html.haml)中使用了@requested_path。至于JSON,如果我确定不想返回完整页面,例如通过ajax,我可以请求返回JSON,并获取错误消息。 - Misu
@misu 这个完美地运作了,你在 config/routes.rb 文件中添加这个的技巧是关键。 - skplunkerin

1
网站图标图片 复制到 app/assets/images 目录下对我有用。

0
在 Rails 7(2023年)中
config/routes.rb
Rails.application.routes.draw do match '*path' => 'errors#error_404', via: :all end
controllers/errors_controller.rb
class ErrorsController < ApplicationController def error_404 render template: 'pages/not_found', status: 404 end end pages/not_found.html.erb

错误404

页面未找到

...但您正在丢失所有活动存储图像!!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接