ActiveRecord: Passing an empty array into NOT IN will return no records

Updated . Posted . Visible to the public. Repeats.

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)
Last edit
Dominik Schöler
Keywords
mysql
License
Source code in this card is licensed under the MIT License.
Posted to makandra dev (2013-04-11 10:04)