在我的控制器中,我经常使用这样的东西来验证project
是否真的属于给定的user
:
private
def authorized_user
@project = Project.find(params[:id])
redirect_to root_path unless current_user?(@project.user)
end
这很好,因为用户A看不到用户B的项目(他被转发到根页面)。
然而,只有当请求了真正存在的project
URL时,这才有效。
例如,URL http://localhost:3000/projects/1
将显示用户的项目,或者转发到根URL(如果另一个用户试图访问该项目)。
但当我试图访问数据库中根本不存在的项目时,,例如:
http://localhost:3000/projects/777
我得到一个丑陋的ActiveRecord::RecordNotFound
错误:
Couldn't find Person with id=777
改善用户体验的最佳方式是什么?
我还从来没有部署过Rails项目,所以我甚至不知道在生产模式下这个错误会是什么样子。
有人能帮忙吗?
谢谢。。。
我个人喜欢使用这个:
@project = Project.where(id: params[:id]).first
若项目不存在,@project
将为零。
尝试:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :render_404
# Render 404 page when record not found
def render_404
render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
end
end
首先,为了避免未经授权的用户访问项目,您应该确定查找方法的范围:
current_user.projects.find(params[:id])
通过这种方式,您将在开发中得到"找不到id为的项目"的错误。为了避免这种情况,您可以使用:
current_user.projects.find_by_id(params[:id])
它返回nil
而不是exception,但有充分的理由说明您通常不应该这样做。在一个写得很好的rails应用程序中,任何用户访问不应该访问的项目的唯一时间是手动更改url中的id。您希望在日志中报告这一点,而不是悄悄跳过。
最后,要抛出403 Forbidden而不是404 Not Found,您可以考虑使用许多授权宝石中的一个(脑海中浮现出Ryan Bates的cancan
)。
编辑:哦,在生产中,ActiveRecord::RecordNotFound将呈现404.html页面,也就是说,这些不是你想要的项目。
根据您想要处理它的方式,您可以使用
@project = Project.find_by_id(params[:id])
如果没有找到记录,这将使@project为nil,并且您将不得不手动处理该情况。
另一个解决方案是抛出404,这是有意义的,因为资源不在那里。您可以在任何控制器(或应用程序控制器)中使用轻松完成此操作
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
def not_found
raise ActionController::RoutingError.new('Not Found')
end
这将导致类似于:
class ApplicationController < ..
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
def not_found
raise ActionController::RoutingError.new('Not Found')
end
end
后一种解决方案将向用户显示默认的404(未找到)错误页面。在第一种情况下,你有更多的控制权,但代价是在任何地方都这样做
希望能有所帮助。