提交 75de1ce1 编写于 作者: J Jon Leighton

Merge pull request #4805 from xuanxu/none_and_null_object_pattern

Added `none` query method to return zero records.
## Rails 4.0.0 (unreleased) ##
* Implemented ActiveRecord::Relation#none method
The `none` method returns a chainable relation with zero records
(an instance of the NullRelation class).
Any subsequent condition chained to the returned relation will continue
generating an empty relation and will not fire any query to the database.
*Juanjo Bazán*
* Added the `ActiveRecord::NullRelation` class implementing the null
object pattern for the Relation class. *Juanjo Bazán*
* Added deprecation for the `:dependent => :restrict` association option.
Please note:
......
......@@ -43,6 +43,7 @@ module ActiveRecord
autoload :AutosaveAssociation
autoload :Relation
autoload :NullRelation
autoload_under 'relation' do
autoload :QueryMethods
......
# -*- coding: utf-8 -*-
module ActiveRecord
# = Active Record Null Relation
class NullRelation < Relation
def exec_queries
@records = []
end
end
end
\ No newline at end of file
......@@ -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
......
......@@ -196,6 +196,39 @@ def lock(locks = true)
relation
end
# Returns a chainable relation with zero records, specifically an
# instance of the NullRelation class.
#
# The returned NullRelation inherits from Relation and implements the
# Null Object pattern so it is an object with defined null behavior:
# it always returns an empty array of records and avoids any database query.
#
# Any subsequent condition chained to the returned relation will continue
# generating an empty relation and will not fire any query to the database.
#
# Used in cases where is needed a method or a scope that could return zero
# results but the response has to be chainable.
#
# For example:
#
# @posts = current_user.visible_posts.where(:name => params[:name])
# # => the visible_post method response has to be a chainable Relation
#
# def visible_posts
# case role
# if 'Country Manager'
# Post.where(:country => country)
# if 'Reviewer'
# Post.published
# if 'Bad User'
# Post.none # => returning [] instead breaks the previous code
# end
# end
#
def none
NullRelation.new(@klass, @table)
end
def readonly(value = true)
relation = clone
relation.readonly_value = value
......
......@@ -215,6 +215,19 @@ def test_select_with_block
assert_equal [2, 4, 6, 8, 10], even_ids.sort
end
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_joins_with_nil_argument
assert_nothing_raised { DependentFirm.joins(nil).first }
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册