Rails ActiveRecord's 'none' method

29 November 2024

The none query method in Rails ActiveRecord is a hidden gem I hadn’t come across until this week.

It creates a relation that returns no results unless combined with other conditions. Without using none I’d have typically created a relation with a where("1=0") condition, and chained .or and .merge calls off it.

The none method provides a cleaner way to do this. If no other conditions are added to the chain it returns an empty result set without querying the database. If other conditions are added, it drops the superfluous WHERE 1=0 condition from the resulting SQL.

Here’s an example

projects = Project.none

projects.to_sql
# => "SELECT `projects`.* FROM `projects` WHERE (1=0)"
# if iterated, no query would actually execute

if include_active?
  projects = projects.or(Project.active)
  projects.to_sql
  # => "SELECT `projects`.* FROM `projects`
  #     WHERE `projects`.`deleted` = FALSE
  #     AND `projects`.`archived` = FALSE"
end

if include_archived?
  projects = projects.or(Project.archived)
  projects.to_sql
  # => "SELECT `projects`.* FROM `projects`
  #     WHERE (`projects`.`deleted` = FALSE
  #       AND `projects`.`archived` = FALSE
  #        OR `projects`.`archived` = TRUE)
  #     ORDER BY name ASC"
end

Note on the generated SQL. It may seem at first glance that the two archived checks are superfluous, but the operator precedence of the AND means that both deleted and archived need to be false to match the first condition.

When this is executed, the resulting SQL doesn’t include a straggling WHERE 1=0 condition, and if no conditions are added to the chain it would just return an empty result set without even querying the database.