我正在使用 Rails 2.3.5,如果我给出Model.find(1)
并且 1 不在数据库中,它会返回 ActiveRecord 错误。它应该nil
像 的情况一样返回Model.find_by_column('..')
吗?
8 回答
这是预期的行为。我认为 David 自己解释得最好,所以这里引用 Ruby, S., Thomas, D. & Hansson, DH, 2009. Agile Web Development with Rails , Third Edition 第三版., Pragmatic Bookshelf (p.330) .
当您使用由主键驱动的查找器时,您正在查找特定记录。你期望它存在。对 Person.find(5) 的调用基于我们对 people 表的了解。我们想要 id 为 5 的行。如果此调用不成功——如果 id 为 5 的记录已被销毁——我们处于异常情况。这要求引发异常,因此 Rails 引发 RecordNotFound。
另一方面,使用条件进行搜索的查找器正在寻找匹配项。所以,Person.find(:first, :conditions=>"name='Dave'") 相当于告诉数据库(作为一个黑盒子)“给我第一个名字为 Dave 的行。” 这展示了一种截然不同的检索方法;我们不确定我们会得到一个结果。结果集完全有可能为空。因此,对于搜索一行的查找器返回 nil 并为搜索多行的查找器返回一个空数组是自然的、非异常的响应。
如果你真的不想要异常,你可以使用find_by_id
:
# @user = User.find(params[:id]) # original code
@user = User.find_by_id(params[:id])
if @user
# found!
else
# not found
end
这应该比单独exists?
检查更快。
编辑:请注意,正如@Miguelgraz 评论的那样,在 Rails 4 中你应该改为User.find_by(id: params[:id])
. 相同的功能,但现在实现不需要method_missing
.
抛出异常是预期的行为。
事实上,在正常的事件过程中,如果您不处理异常,您的 rails 服务器将返回正确的 404 page not found 错误。
如果你想让它返回 nil 你可以自己抓住它:
begin
@model = Model.find(id_provided)
rescue ActiveRecord::RecordNotFound => e
@model = nil
end
如果您希望在查找器方法的 find_by_attributes 风格中抛出异常,您可以使用 bang!方法的版本。
例如,
Model.find_by_category!(a_category_value)
如果找不到匹配项,将抛出 RecordNotFound。
我发现这在 RESTful 控制器等场景中是 DRY 的,在这种情况下,我有一个常见的异常错误处理程序,并且我希望我的操作在未找到与给定参数匹配的资源时表现一致。
您可以在获取记录之前检查记录是否存在。
@model = Model.find(id) if Model.exists?(id)
Rails 4 方法
if user = User.find_by(id: params[:id])
#do something with user
else
#throw error or redirect
raise ActiveRecord::RecordNotFound
end
您可以将find_by与必需的属性(在您的情况下为 id)一起使用,如果未找到给定的 id,这将返回 nil 而不是给出错误。
Model.find_by_id(id_value)
您也可以使用where但您必须知道 where 返回具有零个或多个记录的活动记录关系,您首先需要使用它来仅返回一条记录,或者在零记录返回的情况下返回 nil。
Model.where(id: id_value).first
您可以简单地使用:
user = User.find(10) rescue nil