diff --git a/lib/mongoid/config.rb b/lib/mongoid/config.rb index 978948f07b..aac4ff63fe 100644 --- a/lib/mongoid/config.rb +++ b/lib/mongoid/config.rb @@ -171,6 +171,15 @@ module Config # See https://jira.mongodb.org/browse/MONGOID-5658 for more details. option :around_callbacks_for_embeds, default: false + # When this flag is false, named scopes cannot unset a default scope. + # This is the traditional (and default) behavior in Mongoid 9 and earlier. + # + # Setting this flag to true will allow named scopes to unset the default + # scope. This will be the default in Mongoid 10. + # + # See https://jira.mongodb.org/browse/MONGOID-5785 for more details. + option :allow_scopes_to_unset_default_scope, default: false + # Returns the Config singleton, for use in the configure DSL. # # @return [ self ] The Config singleton. diff --git a/lib/mongoid/scopable.rb b/lib/mongoid/scopable.rb index dac877ad9a..f6624fcd2d 100644 --- a/lib/mongoid/scopable.rb +++ b/lib/mongoid/scopable.rb @@ -294,7 +294,13 @@ def define_scope_method(name) scope = instance_exec(*args, **kwargs, &scoping[:scope]) extension = scoping[:extension] to_merge = scope || queryable - criteria = to_merge.empty_and_chainable? ? to_merge : with_default_scope.merge(to_merge) + + criteria = if Mongoid.allow_scopes_to_unset_default_scope + to_merge + else + to_merge.empty_and_chainable? ? to_merge : with_default_scope.merge(to_merge) + end + criteria.extend(extension) criteria end diff --git a/spec/mongoid/scopable_spec.rb b/spec/mongoid/scopable_spec.rb index 93502c62de..e13490d548 100644 --- a/spec/mongoid/scopable_spec.rb +++ b/spec/mongoid/scopable_spec.rb @@ -3,6 +3,19 @@ require "spec_helper" +# Retrieve the singleton class for the given class. +def singleton_class_for(klass) + class <{ criteria } + Band.scope :unscoped_everyone, -> { unscoped } + Band.scope :removed_default, -> { scoped.remove_scoping(all) } + + Band.create name: 'Depeche Mode' + Band.create name: 'They Might Be Giants' + end + + after do + Band.default_scoping = nil + remove_scope Band, :unscoped_everyone + remove_scope Band, :removed_default + end + + context "when allow_scopes_to_unset_default_scope == false" do # default for <= 9 + config_override :allow_scopes_to_unset_default_scope, false + + it 'merges the default scope into the query with unscoped' do + expect(Band.unscoped_everyone.selector).to include('name' => 'Depeche Mode') + end + + it 'merges the default scope into the query with remove_scoping' do + expect(Band.removed_default.selector).to include('name' => 'Depeche Mode') + end + end + + context "when allow_scopes_to_unset_default_scope == true" do # default for >= 10 + config_override :allow_scopes_to_unset_default_scope, true + + it 'does not merge the default scope into the query with unscoped' do + expect(Band.unscoped_everyone.selector).not_to include('name' => 'Depeche Mode') + end + + it 'does not merge merges the default scope into the query with remove_scoping' do + expect(Band.removed_default.selector).not_to include('name' => 'Depeche Mode') + end + end + end + end end