1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix infinite recursion where a lazy default scope references a scope. Fixes #1264.

This commit is contained in:
Jon Leighton 2011-05-25 00:07:38 +01:00
parent d21fef324b
commit c69111ba5f
4 changed files with 36 additions and 4 deletions

View file

@ -428,6 +428,10 @@ module ActiveRecord #:nodoc:
class_attribute :default_scopes, :instance_writer => false
self.default_scopes = []
# Boolean flag to prevent infinite recursion when evaluating default scopes
class_attribute :apply_default_scope, :instance_writer => false
self.apply_default_scope = true
# Returns a hash of all the attributes that have been specified for serialization as
# keys and their class restriction as values.
class_attribute :serialized_attributes
@ -1261,11 +1265,14 @@ MSG
self.default_scopes = default_scopes + [scope]
end
# The apply_default_scope flag is used to prevent an infinite recursion situation where
# a default scope references a scope which has a default scope which references a scope...
def build_default_scope #:nodoc:
return unless apply_default_scope
self.apply_default_scope = false
if method(:default_scope).owner != Base.singleton_class
# Use relation.scoping to ensure we ignore whatever the current value of
# self.current_scope may be.
relation.scoping { default_scope }
default_scope
elsif default_scopes.any?
default_scopes.inject(relation) do |default_scope, scope|
if scope.is_a?(Hash)
@ -1277,6 +1284,8 @@ MSG
end
end
end
ensure
self.apply_default_scope = true
end
# Returns the class type of the record using the current module as a prefix. So descendants of

View file

@ -424,7 +424,7 @@ module ActiveRecord
end
def with_default_scope #:nodoc:
if default_scoped? && default_scope = @klass.send(:build_default_scope)
if default_scoped? && default_scope = klass.send(:build_default_scope)
default_scope = default_scope.merge(self)
default_scope.default_scoped = false
default_scope

View file

@ -312,6 +312,14 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
end
def test_default_scope_as_class_method_referencing_scope
assert_equal [developers(:david).becomes(ClassMethodReferencingScopeDeveloperCalledDavid)], ClassMethodReferencingScopeDeveloperCalledDavid.all
end
def test_default_scope_as_block_referencing_scope
assert_equal [developers(:david).becomes(LazyBlockReferencingScopeDeveloperCalledDavid)], LazyBlockReferencingScopeDeveloperCalledDavid.all
end
def test_default_scope_with_lambda
assert_equal [developers(:david).becomes(LazyLambdaDeveloperCalledDavid)], LazyLambdaDeveloperCalledDavid.all
end

View file

@ -127,6 +127,21 @@ class ClassMethodDeveloperCalledDavid < ActiveRecord::Base
end
end
class ClassMethodReferencingScopeDeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
scope :david, where(:name => 'David')
def self.default_scope
david
end
end
class LazyBlockReferencingScopeDeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
scope :david, where(:name => 'David')
default_scope { david }
end
class DeveloperCalledJamis < ActiveRecord::Base
self.table_name = 'developers'