Bring back support for passing a callable object to the default_scope macro. You can also just use a block.
This commit is contained in:
parent
6f84c73dc4
commit
019cd51a3f
|
@ -1,5 +1,16 @@
|
||||||
*Rails 3.1.0 (unreleased)*
|
*Rails 3.1.0 (unreleased)*
|
||||||
|
|
||||||
|
* default_scope can take a block, lambda, or any other object which responds to `call` for lazy
|
||||||
|
evaluation:
|
||||||
|
|
||||||
|
default_scope { ... }
|
||||||
|
default_scope lambda { ... }
|
||||||
|
default_scope method(:foo)
|
||||||
|
|
||||||
|
This feature was originally implemented by Tim Morgan, but was then removed in favour of
|
||||||
|
defining a 'default_scope' class method, but has now been added back in by Jon Leighton.
|
||||||
|
The relevant lighthouse ticket is #1812.
|
||||||
|
|
||||||
* Default scopes are now evaluated at the latest possible moment, to avoid problems where
|
* Default scopes are now evaluated at the latest possible moment, to avoid problems where
|
||||||
scopes would be created which would implicitly contain the default scope, which would then
|
scopes would be created which would implicitly contain the default scope, which would then
|
||||||
be impossible to get rid of via Model.unscoped.
|
be impossible to get rid of via Model.unscoped.
|
||||||
|
|
|
@ -1196,6 +1196,15 @@ MSG
|
||||||
# Article.new.published # => true
|
# Article.new.published # => true
|
||||||
# Article.create.published # => true
|
# Article.create.published # => true
|
||||||
#
|
#
|
||||||
|
# You can also use <tt>default_scope</tt> with a block, in order to have it lazily evaluated:
|
||||||
|
#
|
||||||
|
# class Article < ActiveRecord::Base
|
||||||
|
# default_scope { where(:published_at => Time.now - 1.week) }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# (You can also pass any object which responds to <tt>call</tt> to the <tt>default_scope</tt>
|
||||||
|
# macro, and it will be called when building the default scope.)
|
||||||
|
#
|
||||||
# If you need to do more complex things with a default scope, you can alternatively
|
# If you need to do more complex things with a default scope, you can alternatively
|
||||||
# define it as a class method:
|
# define it as a class method:
|
||||||
#
|
#
|
||||||
|
@ -1233,6 +1242,7 @@ end
|
||||||
WARN
|
WARN
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope = Proc.new if block_given?
|
||||||
self.default_scopes = default_scopes.dup << scope
|
self.default_scopes = default_scopes.dup << scope
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1245,6 +1255,8 @@ end
|
||||||
default_scopes.inject(relation) do |default_scope, scope|
|
default_scopes.inject(relation) do |default_scope, scope|
|
||||||
if scope.is_a?(Hash)
|
if scope.is_a?(Hash)
|
||||||
default_scope.apply_finder_options(scope)
|
default_scope.apply_finder_options(scope)
|
||||||
|
elsif !scope.is_a?(Relation) && scope.respond_to?(:call)
|
||||||
|
default_scope.merge(scope.call)
|
||||||
else
|
else
|
||||||
default_scope.merge(scope)
|
default_scope.merge(scope)
|
||||||
end
|
end
|
||||||
|
|
|
@ -312,6 +312,18 @@ class DefaultScopingTest < ActiveRecord::TestCase
|
||||||
assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
|
assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_default_scope_with_lambda
|
||||||
|
assert_equal [developers(:david).becomes(LazyLambdaDeveloperCalledDavid)], LazyLambdaDeveloperCalledDavid.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_scope_with_block
|
||||||
|
assert_equal [developers(:david).becomes(LazyBlockDeveloperCalledDavid)], LazyBlockDeveloperCalledDavid.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_scope_with_callable
|
||||||
|
assert_equal [developers(:david).becomes(CallableDeveloperCalledDavid)], CallableDeveloperCalledDavid.all
|
||||||
|
end
|
||||||
|
|
||||||
def test_default_scope_is_unscoped_on_find
|
def test_default_scope_is_unscoped_on_find
|
||||||
assert_equal 1, DeveloperCalledDavid.count
|
assert_equal 1, DeveloperCalledDavid.count
|
||||||
assert_equal 11, DeveloperCalledDavid.unscoped.count
|
assert_equal 11, DeveloperCalledDavid.unscoped.count
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'ostruct'
|
||||||
|
|
||||||
module DeveloperProjectsAssociationExtension
|
module DeveloperProjectsAssociationExtension
|
||||||
def find_most_recent
|
def find_most_recent
|
||||||
find(:first, :order => "id DESC")
|
find(:first, :order => "id DESC")
|
||||||
|
@ -102,6 +104,21 @@ class DeveloperCalledDavid < ActiveRecord::Base
|
||||||
default_scope where("name = 'David'")
|
default_scope where("name = 'David'")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class LazyLambdaDeveloperCalledDavid < ActiveRecord::Base
|
||||||
|
self.table_name = 'developers'
|
||||||
|
default_scope lambda { where(:name => 'David') }
|
||||||
|
end
|
||||||
|
|
||||||
|
class LazyBlockDeveloperCalledDavid < ActiveRecord::Base
|
||||||
|
self.table_name = 'developers'
|
||||||
|
default_scope { where(:name => 'David') }
|
||||||
|
end
|
||||||
|
|
||||||
|
class CallableDeveloperCalledDavid < ActiveRecord::Base
|
||||||
|
self.table_name = 'developers'
|
||||||
|
default_scope OpenStruct.new(:call => where(:name => 'David'))
|
||||||
|
end
|
||||||
|
|
||||||
class ClassMethodDeveloperCalledDavid < ActiveRecord::Base
|
class ClassMethodDeveloperCalledDavid < ActiveRecord::Base
|
||||||
self.table_name = 'developers'
|
self.table_name = 'developers'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue