我有一个像这样的查询:
Tag.where('id not IN (?)', current_user.tags.pluck(:id)).uniq
什么时候
current_user.tags.pluck(:id)).uniq
返回 NULL,我从 Tag 查询中没有得到任何结果,这不是所需的行为。
我在这里做错了什么?
谢谢。
我有一个像这样的查询:
Tag.where('id not IN (?)', current_user.tags.pluck(:id)).uniq
什么时候
current_user.tags.pluck(:id)).uniq
返回 NULL,我从 Tag 查询中没有得到任何结果,这不是所需的行为。
我在这里做错了什么?
谢谢。
我认为不会current_user.tags.pluck(:id)
返回 a nil
,而是返回一个空数组。ActiveRecord 将在该上下文中将空数组视为 NULL。结果是一些无意义的 SQL,如下所示:
select tags.* from tags where id in (null)
由于 SQL 的 NULL 的特性(特别是对于 allx = NULL
都x != NULL
为 false x
),WHERE 子句中的in (null)
ornot in (null)
不会匹配任何内容。
将 Ruby 转换为的 Rails[]
非常NULL
愚蠢(更多关于这里的讨论)但即使它足够聪明地引发异常,您仍然必须手动处理“空数组”情况,如下所示:
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
在那里,SQLin
运算符会将其 RHS 视为一个集合,因此重复项将在幕后折叠。
where.not
当传入的参数为空数组时,用于让 Rails 处理。正如mu 太短指出的那样,当传递给查询条件的值是一个空数组时,ActiveRecord 会将其转换为NULL
使您的查询混乱的值,并且始终返回一个空结果。
处理这个问题的旧方法是有条件地检查一个空数组作为参数,而不是添加这个条件。然而,随着 Rails 4 的引入where.not
,我们不再需要这个检查。
我们可以简单地做:
Tag.where.not( id: current_user.tags.pluck(:id) ).uniq
现在 ActiveRecord 将自动检查一个空数组,当它看到它时,条件变为1=1
,这本质上是没有意义的,但更重要的是,它只是被忽略,其余的查询将运行,就好像该条件从未添加到查询中一样.