aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-04-18 23:35:22 +0100
committerJon Leighton <j@jonathanleighton.com>2011-04-18 23:35:22 +0100
commit019cd51a3f36ec7631bf1b63c069e62a3b5185d4 (patch)
tree6bdb235ccdd5389b381e129fdeef3582db71175e /activerecord
parent6f84c73dc48538202766cff3d973a53d3c30848e (diff)
downloadrails-019cd51a3f36ec7631bf1b63c069e62a3b5185d4.tar.gz
rails-019cd51a3f36ec7631bf1b63c069e62a3b5185d4.tar.bz2
rails-019cd51a3f36ec7631bf1b63c069e62a3b5185d4.zip
Bring back support for passing a callable object to the default_scope macro. You can also just use a block.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG11
-rw-r--r--activerecord/lib/active_record/base.rb12
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb12
-rw-r--r--activerecord/test/models/developer.rb17
4 files changed, 52 insertions, 0 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 4ae82a6419..9ff29f1155 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,16 @@
*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
scopes would be created which would implicitly contain the default scope, which would then
be impossible to get rid of via Model.unscoped.
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 5b316c17be..9a01d793f9 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1196,6 +1196,15 @@ MSG
# Article.new.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
# define it as a class method:
#
@@ -1233,6 +1242,7 @@ end
WARN
end
+ scope = Proc.new if block_given?
self.default_scopes = default_scopes.dup << scope
end
@@ -1245,6 +1255,8 @@ end
default_scopes.inject(relation) do |default_scope, scope|
if scope.is_a?(Hash)
default_scope.apply_finder_options(scope)
+ elsif !scope.is_a?(Relation) && scope.respond_to?(:call)
+ default_scope.merge(scope.call)
else
default_scope.merge(scope)
end
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index e231371cf8..2ed676fe69 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -312,6 +312,18 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
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
assert_equal 1, DeveloperCalledDavid.count
assert_equal 11, DeveloperCalledDavid.unscoped.count
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 93363f47c5..10701dd6fd 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -1,3 +1,5 @@
+require 'ostruct'
+
module DeveloperProjectsAssociationExtension
def find_most_recent
find(:first, :order => "id DESC")
@@ -102,6 +104,21 @@ class DeveloperCalledDavid < ActiveRecord::Base
default_scope where("name = 'David'")
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
self.table_name = 'developers'