在我的控制器中,我使用了类似的东西来验证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 http://localhost:3000/projects/1
将显示用户的项目或转发到根URL(如果其他用户尝试访问该项目)。
但是当我尝试访问数据库中根本不存在的项目时,例如像这样:
http://localhost:3000/projects/777
...我收到一个丑陋的ActiveRecord::RecordNotFound
错误:
Couldn't find Person with id=777
在这里改善用户体验的最佳方法是什么?
我还没有实际部署一个Rails项目,所以我甚至不知道这个错误在生产模式下会是什么样子。
有人可以帮忙吗?
...谢谢
答案 0 :(得分:5)
我个人喜欢用这个:
@project = Project.where(id: params[:id]).first
如果项目不存在,@project
将为零。
答案 1 :(得分:2)
根据您的处理方式,您可以使用
@project = Project.find_by_id(params[:id])
如果没有找到记录,这将使@project为零,并且您将手动处理该案例。
另一个解决方案是抛出一个有意义的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(NOT FOUND)错误页面。在第一种情况下,你有更多的控制权,但代价是无处不在
希望有所帮助。
答案 2 :(得分:1)
首先,为避免未授权用户访问项目,您应该确定查找方法的范围:
current_user.projects.find(params[:id])
这样,您将在开发过程中遇到“无法找到带ID的项目”错误。为避免这种情况,您可以使用:
current_user.projects.find_by_id(params[:id])
返回nil
而不是异常,但有充分的理由说明你通常不应该这样做。在一个编写良好的rails应用程序中,任何用户访问项目的唯一时间他不应该是他手动更改URL中的id。您希望在日志中报告此内容,而不是以静默方式跳过。
最后,要投掷403 Forbidden而不是404 Not Found,您可以考虑使用众多授权宝石中的一种(Ryan Bates想到cancan
)。
编辑:哦,在制作中,ActiveRecord :: RecordNotFound将呈现404.html页面,例如,这些不是您正在寻找的项目。
答案 3 :(得分:1)
尝试:
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