Caution when using .where
to exclude records from a scope like this:
# Fragile - avoid
User.where("id NOT IN (?)", excluded_ids)
When the exclusion list is empty, you would expect this to return all records. However, this is not what happens:
# Broken example
User.where("id NOT IN (?)", []).to_sql
=> SELECT `users`.* FROM `users` WHERE (id NOT IN (NULL))
Passing an empty exclusion list returns no records at all! See below for better implementations.
Rails 4+
Use the .not
method to let Rails do the logic
# Good
User.where.not(id: []).to_sql
=> SELECT "users".* FROM "users" WHERE (1=1)
User.where.not(id: [1]).to_sql
=> SELECT "users".* FROM "users" WHERE ("users"."id" != 1)
User.where.not(id: [1, 2]).to_sql
=> SELECT "users".* FROM "users" WHERE "users"."id" NOT IN (1, 2)
Rails < 4
Before Rails 4, you needed to work around this yourself:
# Good
excluded_ids.blank? ? User.all : User.where("id NOT IN (?)", excluded_ids)
Posted to makandra dev (2013-04-11 10:04)