4

我有一个像这样的查询:

Tag.where('id not IN (?)', current_user.tags.pluck(:id)).uniq

什么时候

current_user.tags.pluck(:id)).uniq

返回 NULL,我从 Tag 查询中没有得到任何结果,这不是所需的行为。

我在这里做错了什么?

谢谢。

4

2 回答 2

3

我认为不会current_user.tags.pluck(:id)返回 a nil,而是返回一个空数组。ActiveRecord 将在该上下文中将空数组视为 NULL。结果是一些无意义的 SQL,如下所示:

select tags.* from tags where id in (null)

由于 SQL 的 NULL 的特性(特别是对于 allx = NULLx != 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 视为一个集合,因此重复项将在幕后折叠。

于 2013-09-22T22:55:08.443 回答
1

where.not当传入的参数为空数组时,用于让 Rails 处理。

正如mu 太短指出的那样,当传递给查询条件的值是一个空数组时,ActiveRecord 会将其转换为NULL使您的查询混乱的值,并且始终返回一个空结果。

处理这个问题的旧方法是有条件地检查一个空数组作为参数,而不是添加这个条件。然而,随着 Rails 4 的引入where.not,我们不再需要这个检查。

我们可以简单地做:

Tag.where.not( id: current_user.tags.pluck(:id) ).uniq

现在 ActiveRecord 将自动检查一个空数组,当它看到它时,条件变为1=1,这本质上是没有意义的,但更重要的是,它只是被忽略,其余的查询将运行,就好像该条件从未添加到查询中一样.

于 2020-01-07T04:54:55.050 回答