Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


none query method #4609

wants to merge 1 commit into from

4 participants

Juanjo Bazán Ben Woosley Aaron Patterson Jon Leighton
Juanjo Bazán

Here is a none method to return an empty relation from a AR model (i.e Post.none), as previously discussed here: #4548

It prevents the query hitting the database, is chainable and makes any subsequent relation empty, so Post.none.where(:author_id => 1) is also empty.

Ben Woosley

You might want to just update the code in the original pull request, to keep the conversation together there.

BTW I'm +1 on this idea. .where('1 = 0') is a lame hack.

Aaron Patterson

I'm OK with this, but I'd like more opinions. @jonleighton ?

Jon Leighton

I'm okay with this too, but I think it would be better if:

  • The rationale was explained in the documentation (also explained in terms of the 'null object pattern' as that's what this is)
  • There was a CHANGELOG entry
  • Ideally I'd prefer if we used polymorphism. I.e. if Relation#none returned an instance of a NullRelation that implemented this behaviour, rather than having to have a @none_value var and special code in exec_queries.


Aaron Patterson

I agree with @jonleighton. @xuanxu can you make those changes, and we'll merge it in. Thanks for the contribution! :-)

Juanjo Bazán

OK, I will try to make those changes

Juanjo Bazán

@tenderlove Done!: #4768
¿should I backport it to 3.2?

Aaron Patterson

@jonleighton can you review?

@xuanxu no, we will not backport this (as it is a new feature).

Juanjo Bazán xuanxu closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 23, 2012
  1. Juanjo Bazán
This page is out of date. Refresh to see the latest.
2  activerecord/lib/active_record/querying.rb
@@ -8,7 +8,7 @@ module Querying
delegate :find_each, :find_in_batches, :to => :scoped
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
- :having, :create_with, :uniq, :references, :to => :scoped
+ :having, :create_with, :uniq, :references, :none, :to => :scoped
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :to => :scoped
# Executes a custom SQL query against your database and returns all the results. The results will
6 activerecord/lib/active_record/relation.rb
@@ -8,7 +8,7 @@ class Relation
JoinOperation =, :join_class, :on)
ASSOCIATION_METHODS = [:includes, :eager_load, :preload]
MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having, :bind, :references]
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq]
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq, :none]
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
@@ -166,7 +166,9 @@ def exec_queries
default_scoped = with_default_scope
- if default_scoped.equal?(self)
+ if @none_value
+ @records = []
+ elsif default_scoped.equal?(self)
@records = if @readonly_value.nil? && !@klass.locking_enabled?
eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values)
13 activerecord/lib/active_record/relation/query_methods.rb
@@ -10,7 +10,7 @@ module QueryMethods
:where_values, :having_values, :bind_values,
:limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value,
:from_value, :reordering_value, :reverse_order_value,
- :uniq_value, :references_values
+ :uniq_value, :references_values, :none_value
def includes(*args)
args.reject! {|a| a.blank? }
@@ -196,6 +196,17 @@ def lock(locks = true)
+ # Returns a chainable empty relation with zero records. It prevents the
+ # execution of the query.
+ #
+ # Any subsequent condition chained to the relation will continue
+ # generating an empty relation and will not fire any query to the database.
+ def none
+ relation = clone
+ relation.none_value = true
+ relation
+ end
def readonly(value = true)
relation = clone
relation.readonly_value = value
2  activerecord/test/cases/relation_test.rb
@@ -20,7 +20,7 @@ def test_construction
def test_single_values
- assert_equal [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq].map(&:to_s).sort,
+ assert_equal [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq, :none].map(&:to_s).sort,
13 activerecord/test/cases/relations_test.rb
@@ -210,6 +210,19 @@ def test_finding_with_group
assert_equal 4,
+ def test_none
+ assert_no_queries do
+ assert_equal [], Developer.none
+ assert_equal [], Developer.scoped.none
+ end
+ end
+ def test_none_chainable
+ assert_no_queries do
+ assert_equal [], Developer.none.where(:name => 'David')
+ end
+ end
def test_select_with_block
even_ids = {|d| % 2 == 0 }.map(&:id)
assert_equal [2, 4, 6, 8, 10], even_ids.sort
Something went wrong with that request. Please try again.