Changes
-Be careful with the Active Record `where` method. When you accidentally pass an empty array to the `where` method using `NOT IN`, you probably will not get what you expected:- +Caution when using `.where` to exclude records from a scope like this:
- +```rb
- +# 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:
- ```rb
-User.where("id NOT IN (?)", [])- +# Broken example
- +User.where("id NOT IN (?)", []).to_sql
- => SELECT `users`.* FROM `users` WHERE (id NOT IN (NULL))
- ```
--Even though you might expect this to return all records, this actually results none.--**Never use the expression `id NOT IN (?)` without taking care of this case**! See below some workarounds.- +**Passing an empty exclusion list returns no records at all!** See below for better implementations.
- +## Rails 4+
-## Rails >= 4--If you use the same expression as above in Rails >= 4, it is still broken. But you can use the `.not` method to work around this issue.- +Use the `.not` method to let Rails do the logic
- ```rb
- +# 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)
-puts User.where.not(id: [1, 2]).to_sql- +User.where.not(id: [1, 2]).to_sql
- => SELECT "users".* FROM "users" WHERE "users"."id" NOT IN (1, 2)
- ```
-- ## Rails < 4
-Rails < 4 does not provide a pretty workaround.-- +Before Rails 4, you needed to workaround this yourself:
- ```rb
-ids = []--if ids.present?- User.where("id NOT IN (?)", ids)-else- User.all-end- +# Good
- +excluded_ids.blank? ? User.all : User.where("id NOT IN (?)", excluded_ids)
- ```
Posted by Dominik Schöler to makandra dev (2025-02-17 09:08)