在Ruby on Rails中处理没有ID错误的最佳方式是什么?

问题描述:

在我的控制器,我使用这样大量来验证project真正属于给定user在Ruby on Rails中处理没有ID错误的最佳方式是什么?

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项目,所以我甚至不知道这个错误将在生产模式下看起来像什么。

任何人都可以帮忙吗?

谢谢...

我个人很喜欢用这样的:

@project = Project.where(id: params[:id]).first 

如果项目不存在,@project将是零。

+0

好的,谢谢!在这种情况下,“first”究竟做了什么?我以为'第一'选择第一个记录...但是我是一个n00b ... – Tintin81 2013-02-14 19:47:41

+0

好吧,为了补救你的无聊,请阅读本指南:[Query Interface](http://guides.rubyonrails.org/active_record_querying。 HTML)。你会在那里找到答案。 :) – 2013-02-14 19:51:21

+0

好的,我明白了。它返回'nil'而不是抛出异常。但是我必须在下一行测试nil值,然后...... – Tintin81 2013-02-14 20:25:29

根据您要如何处理它,你可以使用

@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找到)错误页面。在第一种情况下,你有更多的控制权,但是以无所不在的代价

希望有帮助。

+0

我认为你的第二种解决方案要好得多,因为它不涉及修改脚手架生成的代码,并且可以在应用程序控制器中用几行完成干净地实现。 – bdares 2013-02-14 19:48:44

+0

你的意思是塞尔吉奥的解决方案更好?好的,但我如何将这个添加到应用程序控制器中? – Tintin81 2013-02-14 20:29:11

+0

编辑我的回复使其更清晰。 – Novae 2013-02-14 20:49:58

首先,以避免未经授权的用户访问项目,就请您范围查找方法:

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页面,也就是这些不是你正在寻找的项目。

+0

你在这里做的很好。非常感谢你的帮助!哇,有很多非常好的答案可以在这个线程中选择... – Tintin81 2013-02-15 10:55:15

+0

只需要明确将响应重定向到404.html - 它们是很好的示例,如何更改默认行为,但在此不需要它们案件。正如我所说的,在生产中,Rails默认是这样做的。而在开发中,您希望获得例外页面,而不是404页面。 – Pandaamonium 2013-02-15 15:31:01

尝试:

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 
+0

谢谢你的帮助! – Tintin81 2013-02-15 10:52:05