Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I just recently discovered a neat trick to replace greater than / less than in rails where in which you can use a range to replace the string version of where:

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

can be replaced with:

Post.where(id: ..10)

and three dots changes it from <= to <

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

can be replaced with:

Post.where(id: ...10)

this trick seems to work for:

  • less than or equal to <=
  • less than <
  • greater than or equal to >=

HOWEVER it does not work for greater than > because:

Post.where(id: 10..) and Post.where(id: 10...) will both search for greater than or equal to.

My question is, is there a way to get this to work for greater than (other than hacking it with + 1?):

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

My assumption is that the answer is no, but I still wanted to ask!

Here is a full example of what I am talking about:


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

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

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

# NOTE: THIS STILL ONLY GOES >=, NOT > 
Post.where(id: 1...)
=>   Post Load (0.4ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" >= $1  [["id", 1]]
like image 281
Clark Taylor Avatar asked Jan 28 '26 15:01

Clark Taylor


1 Answers

You can use 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

Note that Post.where(id: (10+1)..) works because the id is an integer column. However, this will not work for decimal columns, such as Post.where('average_rating > 3.0'). Using Post.where(average_rating: (3.0+1)..) will look for average ratings > 4 but skips posts with average rating of 3.5. Post.where.not(average_rating: ..3.0) will result in the correct query.

like image 57
AbM Avatar answered Jan 31 '26 06:01

AbM