要获得publisher_id
等于 10、16 或 17 的所有帖子,我做到了:
Post.where(:publisher_id => [10, 16, 17])
我将如何获得publisher_id
不等于 10、16 或 17 的所有帖子(即除这三个之外的所有可能 ID)?
只需执行:
Post.where(["publisher_id NOT IN (?)", [10, 16, 17]])
在 rails 4 中我们可以像下面这样做
Post.where.not(:publisher_id => [10, 16, 17])
它将生成如下所示的 SQL
SELECT "posts".* FROM "posts" WHERE ("posts"."publisher_id" NOT IN (10, 16, 17))
未经测试,但应该像(使用 metawhere gem):
Post.where( :id.not_eq => [10,16,17] )
使用 Rails 3 的 Arel 中加入的"纯"ActiveRecord 语法,您可以执行以下操作:
Post.where( Post.arel_table[:publisher_id].not_in([10, 16, 17]) )
我用过的简洁解决方案:
ids = #however you get the IDS
Post.where(["id not in (?)", [0,*ids])
- 0 的存在意味着它总是有一个元素(假设没有任何东西的 ID 为 0)
- ID 变成一个 splat 意味着它将永远是一个数组。
此页面上的每个答案都是错误的,因为这些答案都不能处理所有数组情况,尤其是只有一个元素的数组。
下面是一个使用此页面上的任何"所谓的"解决方案都会失败的示例:
@ids = [1]
Post.where("publisher_id NOT IN (?)", @ids)
#ERROR
Post.where("publisher_id NOT IN (?)", [4])
#ERROR
#...etc
#ALSO
@ids = []
Post.where("publisher_id NOT IN (?)", @ids)
#ERROR
Post.where("publisher_id NOT IN (?)", [])
#ERROR
#...etc
#The problem here is that when the array only has one item, only that element is
#returned, NOT an array, like we had specified
#Part of the sql that is generated looks like:
#...WHERE (publisher_id NOT IN 166)
#It should be:
#...WHERE (publisher_id NOT IN (166))
本页上唯一真正走在正确轨道上并处理这个非常重要的案例的答案是康斯坦丁@Tudor。但问题是他实际上并没有展示使用他的方法来解决OP发布的真正抽象示例问题的"方法"(而不仅仅是使用硬编码数字)。
这是我的解决方案,可以动态查找不在 Activerecord 关联中的 ID,给定要排除的 id 数组,这将与 n 个元素的数组一起使用(...包括 n=1 和 n=0)
@ids = [166]
@attribute = "publisher_id"
@predicate = "NOT IN"
@ids = "(" + @ids.join(",") + ")"
if @ids == "()"
#Empty array, just set @ids, @attribute, and @predicate to nil
@ids = @attribute = @predicate = nil
end
#Finally, make the query
Post.where( [@attribute, @predicate, @ids].join(" ") )
#Part of the sql that is generated looks like:
#...WHERE (publisher_id NOT IN (166))
#CORRECT!
#If we had set @ids = [] (empty array)
#Then the if statement sets everything to nil, and then
#rails removes the blank " " space in the where clause automatically and does
#the query as if all records should be returned, which
#logically makes sense!
Post.where(" id NOT IN ( 10, 16, 17) ")