Rails "Where" 方法 - 大于 (">") 使用无限范围

Rails "Where" method - greater than (">") using endless ranges

我最近发现了一个巧妙的技巧来替换 rails where 中的大于/小于,您可以在其中使用范围替换 where:

的字符串版本

Post.where('id <= ?', 10)

可以替换为:

Post.where(id: ..10)

三个点将其从 <= 更改为 <

Post.where('id < ?', 10)

可以替换为:

Post.where(id: ...10)

这个技巧似乎适用于:

但是它不适用于大于 > 因为:

Post.where(id: 10..)Post.where(id: 10...) 都将搜索大于或等于。

我的问题是,有没有一种方法可以让它工作超过(除了用 + 1 破解它?):

Post.where(id: (10+1)..)

我的假设是答案是否定的,但我还是想问!

下面是我所说内容的完整示例:


Post.where(id: ..9)
=>   Post Load (0.3ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" <=   [["id", 9]]

Post.where(id: ...9)
=>   Post Load (0.3ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" <   [["id", 9]]

Post.where(id: 1..)
=>   Post Load (0.4ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" >=   [["id", 1]]

# NOTE: THIS STILL ONLY GOES >=, NOT > 
Post.where(id: 1...)
=>   Post Load (0.4ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" >=   [["id", 1]]

您可以使用where.not

Post.where.not(id: ..10).to_sql
# => SELECT "posts".* FROM "posts" WHERE "posts"."id" > 10
Post.where.not(id: ...10).to_sql
# => SELECT "posts".* FROM "posts" WHERE "posts"."id" >= 10

请注意,Post.where(id: (10+1)..) 有效,因为 id 是整数列。但是,这不适用于小数列,例如 Post.where('average_rating > 3.0')。使用 Post.where(average_rating: (3.0+1)..) 将查找平均评分 > 4 的帖子,但会跳过平均评分为 3.5 的帖子。 Post.where.not(average_rating: ..3.0) 将产生正确的查询。

问题的主要目的是试图避免将长查询更改为“字符串”方法:

# good
Post.where(name: name, type: type, whatever: whatever)

# bad - uses string approach
Post.where('name = :name AND type = :type AND whatever = :whatever',
           name: name, type: type, whatever: whatever)

如果大于需要,一种解决此问题并使其可读的方法是将查询拆分为 2 个单独的 where 方法:

# good - only uses string approach with greater than which is more 
# readable that where.not
Post.where(name: name, type: type, whatever: whatever).where('id > ?', 10)

# bad - uses string method
Post.where('name = :name AND type = :type AND whatever = :whatever AND id > :id',
           name: name, type: type, whatever: whatever, id: 10)

# bad - where.not is not very readable
Post.where(name: name, type: type, whatever: whatever).where.not(id: ..10)