我有一个类似的查询:
Tag.where('id not IN (?)', current_user.tags.pluck(:id)).uniq
何时
current_user.tags.pluck(:id)).uniq
返回NULL,我没有从Tag查询中得到任何结果,这不是期望的行为。
我在这里做错了什么?
谢谢。
我不认为current_user.tags.pluck(:id)
返回一个nil
,它返回一个空数组。在这种情况下为ActiveRecord will treat an empty array as a NULL。结果是一些像这样的荒谬的SQL:
select tags.* from tags where id in (null)
由于SQL的NULL的特质(特别是x = NULL
和x != NULL
对所有x
均为假),WHERE子句中的in (null)
或not in (null)
不会匹配任何内容。
[将Ruby的[]
转换为NULL
的过程非常愚蠢(关于over here的更多讨论),但是即使它足够聪明地引发了异常,您仍然必须处理“空数组”的情况手动输入以下内容:
tag_ids = current_user.tags.pluck(:id)
if(tag_ids.empty?)
tags = Tag.all
else
tags = Tag.where('id not in (?)', tag_ids)
end
而且您不需要那里的uniq
,SQL in
运算符会将其RHS视为一个集合,因此重复项将被隐藏在后台。
where.not
让Rails处理。由于mu太短指出,当传递给查询条件的值是一个空数组时,ActiveRecord会将其转换为NULL
,这会使您的查询混乱,并且将始终返回空结果。
处理此问题的旧方法是有条件地检查一个空数组作为参数,而不添加此条件。但是,在引入where.not
的Rails 4中,我们不再需要进行此检查。
我们可以简单地做:
Tag.where.not( id: current_user.tags.pluck(:id) ).uniq
现在ActiveRecord将自动检查一个空数组,当它看到它时,条件变为1=1
,这本质上是没有意义的,但更重要的是,它将被忽略,并且您的其余查询将像该条件被执行一样运行从未添加到查询中。