在Rails控制器中检查记录是否存在

101

在我的应用程序中,用户可以创建一个业务。当他们触发BusinessesController中的index操作时,我想检查业务是否与current_user.id相关:

  • 如果是:显示业务。
  • 如果不是:重定向到new操作。

我尝试使用以下代码:

if Business.where(:user_id => current_user.id) == nil
  # no business found
end

但即使业务不存在,它始终返回true...

我该如何测试数据库中是否存在记录?


1
使用 where 如果没有记录将返回一个空数组。而 [] 不等于 nil - mind.blank
那么只需要一个 unless Business.find_by_user_id(current_user.id) 呢? - Hengjie
可能是Checking if ActiveRecord find returns a result的重复问题。 - Ciro Santilli OurBigBook.com
8个回答

255

为什么你的代码不起作用?

where 方法返回一个 ActiveRecord::Relation 对象 (类似于包含 where 结果的数组),它可能为空,但永远不会是 nil

Business.where(id: -1) 
 #=> returns an empty ActiveRecord::Relation ( similar to an array )
Business.where(id: -1).nil? # ( similar to == nil? )
 #=> returns false
Business.where(id: -1).empty? # test if the array is empty ( similar to .blank? )
 #=> returns true

如何测试是否存在至少一条记录?

选项 1: 使用 .exists?

if Business.exists?(user_id: current_user.id)
  # same as Business.where(user_id: current_user.id).exists?
  # ...
else
  # ...
end

选项 2: 使用.present?(或 .blank?.present? 的相反)

if Business.where(:user_id => current_user.id).present?
  # less efficiant than using .exists? (see generated SQL for .exists? vs .present?)
else
  # ...
end

选项 3:在 if 语句中进行变量赋值

if business = Business.where(:user_id => current_user.id).first
  business.do_some_stuff
else
  # do something else
end

这个选项可能被一些代码检查工具(例如Rubocop)视为代码异味。

选项3b:变量赋值

business = Business.where(user_id: current_user.id).first
if business
  # ...
else
  # ...
end

你也可以使用 .find_by_user_id(current_user.id) 代替 .where(...).first


最佳选项:

  • 如果你不使用 Business 对象: 选项1
  • 如果你需要使用 Business 对象: 选项3

似乎没有起作用。它一直通过那个测试并加载index.html,就像使用== nil测试一样(所以我得到一个错误:未定义的方法`name' for nil:NilClass)。 - user470763
在调用 present 之前先尝试使用 first。 - MrYoshiji
哦,那是我的错,我混淆了,你需要使用“blank?”进行测试。 - MrYoshiji
谢谢,那个方法可行!我不应该犯那个错误。你能告诉我为什么“== nil”检查没有起作用吗? - user470763
好的,请给我一分钟,我会更新我的答案,同时在.blank?之前不要使用.first ;) - MrYoshiji
我没有删除第一个。感谢您的帮助。 - user470763

30

在这种情况下,我喜欢使用ActiveRecord提供的exists?方法:

Business.exists? user_id: current_user.id

存在吗?可以使用OR吗? - Imran Ahmad

5

使用'exists?'

Business.exists? user_id: current_user.id #=> 1 or nil

使用 'any?':

Business.where(:user_id => current_user.id).any? #=> true or false

如果您使用带有.where的内容,请确保避免作用域问题,最好使用.unscoped

Business.unscoped.where(:user_id => current_user.id).any?

最好使用Business.unscoped.where(:user_id => current_user.id).pluck(:id).any?来避免不必要的关联加载,以检查您正在检查的对象。 - Juanin

1
business = Business.where(:user_id => current_user.id).first
if business.nil?
# no business found
else
# business.ceo = "me"
end

1
当您调用 Business.where(:user_id => current_user.id) 时,您将获得一个数组。这个数组可能没有对象,也可能有一个或多个对象,但它不会是 null。因此,检查 == nil 将永远不会为真。
您可以尝试以下内容:
if Business.where(:user_id => current_user.id).count == 0

所以你需要检查数组中元素的数量并将其与零进行比较。
或者你可以尝试:
if Business.find_by_user_id(current_user.id).nil?

这会返回一个值,可能是一或零。


1
ActiveRecord#where会返回一个ActiveRecord::Relation对象(它永远不会是nil)。尝试在关系上使用.empty?来测试它是否会返回任何记录。

0
如果你需要使用对象的实例变量来操作,我会这样做:
if @business = Business.where(:user_id => current_user.id).first
  #Do stuff
else
  #Do stuff
end

0

有些新东西可以尝试 (:

分配一个变量或返回

return unless @business = Business.where(user_id: current_user.id).first

如果当前用户ID没有找到任何业务,该方法会在此处退出,或将实例变量 @business 分配给第一个业务对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接