首先需要修改项目的配置,让项目接收到错误提示时,从 route 中寻找,而不直接读 public 的文件:
# config/application.rb
config.exceptions_app = self.routes
加入配置之后,避免在读取到/404
, /422
, /500
时,仍然从 public 中寻找,建议删除 public 下的这三个 html 文件。
因为 public 的对应错误信息页面删除了,所以需要重新定义错误信息的 Route:
# config/routes.rb
%w(404 422 500).each do |code|
get code, to: "errors#show", code: code
end
在加好 Errors 后,自然需要对应的 Controller 文件:
class ErrorsController < ApplicationController
def show
render status_code.to_s, status: status_code
end
protected
def status_code
params[:code] || 500
end
end
这样就会根据错误的提示,去 render 对应的模板,如出现 404 错误,则去寻找errors/404.html.erb
,所以加入相应的404.html.erb
, 422.html.erb
, 500.html.erb
。参考:
# app/views/errors/404.html.haml
%h1 404 - Not Found
因为开发环境下出现错误,都会呈现对应的错误信息,包括代码位置等。而不会弹出 404 或 500 页面,其实要在开发环境下,检测这些页面也是很方便的:
# config/environments/development.rb
config.consider_all_requests_local = false
只需要把上面的设置从 true 改为 false 就可以了。
当把错误自定义以 route 的方式展现后,如果本来的错误信息页面,例如 404 页面出错了,就会出现这样的错误:
"500 Internal Server Error\n" \
"If you are the administrator of this website, then please read this web " \
"application's log file and/or the web server's log file to find out what " \
"went wrong."
这个问题就像刚刚上面说的,是因为你的错误提示信息页面出错了,无法展现 404 页面了,所以就调用了 Rails 下的一个 500 错误提示信息,源码位置在:show_exceptions.rb#L18-L22。 所以,如果出现了这样的错误,需要仔细看看自己的错误信息页面是否在哪里出了问题。
*我在一个开源项目里,也加入了此功能,可以浏览对应的 commit,位置在:Merge branch 'dynamic_error_pages'。