module Mongoid::Scoping::ClassMethods

Public Instance Methods

criteria()
Alias for: with_default_scope
default_scopable?() click to toggle source

Is the class able to have the default scope applied?

@example Can the default scope be applied?

Band.default_scopable?

@return [ true, false ] If the default scope can be applied.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 78
def default_scopable?
  default_scoping? && !Threaded.executing?(:without_default_scope)
end
default_scope(value) click to toggle source

Add a default scope to the model. This scope will be applied to all criteria unless unscoped is specified.

@example Define a default scope with a criteria.

class Band
  include Mongoid::Document
  field :active, type: Boolean
  default_scope where(active: true)
end

@example Define a default scope with a proc.

class Band
  include Mongoid::Document
  field :active, type: Boolean
  default_scope ->{ where(active: true) }
end

@param [ Proc, Criteria ] scope The default scope.

@raise [ Errors::InvalidScope ] If the scope is not a proc or criteria.

@return [ Proc ] The default scope.

@since 1.0.0

# File lib/mongoid/scoping.rb, line 65
def default_scope(value)
  check_scope_validity(value)
  self.default_scoping = process_default_scope(value)
end
queryable() click to toggle source

Get a queryable, either the last one on the scope stack or a fresh one.

@api private

@example Get a queryable.

Model.queryable

@return [ Criteria ] The queryable.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 92
def queryable
  scope_stack.last || Criteria.new(self)
end
scope(name, value, &block) click to toggle source

Create a scope that can be accessed from the class level or chained to criteria by the provided name.

@example Create named scopes.

class Person
  include Mongoid::Document
  field :active, type: Boolean
  field :count, type: Integer

  scope :active, where(active: true)
  scope :at_least, ->(count){ where(:count.gt => count) }
end

@param [ Symbol ] name The name of the scope. @param [ Proc, Criteria ] conditions The conditions of the scope.

@raise [ Errors::InvalidScope ] If the scope is not a proc or criteria. @raise [ Errors::ScopeOverwrite ] If the scope name already exists.

@since 1.0.0

# File lib/mongoid/scoping.rb, line 117
def scope(name, value, &block)
  normalized = name.to_sym
  check_scope_validity(value)
  check_scope_name(normalized)
  _declared_scopes[normalized] = {
    scope: strip_default_scope(value),
    extension: Module.new(&block)
  }
  define_scope_method(normalized)
end
scope_stack() click to toggle source

Initializes and returns the current scope stack.

@example Get the scope stack.

Person.scope_stack

@return [ Array<Criteria> ] The scope stack.

@since 1.0.0

# File lib/mongoid/scoping.rb, line 136
def scope_stack
  Threaded.scope_stack[object_id] ||= []
end
scoped(options = nil) click to toggle source

Get a criteria for the document with normal scoping.

@example Get the criteria.

Band.scoped(skip: 10)

@note This will force the default scope to be applied.

@param [ Hash ] options Query options for the criteria.

@option options [ Integer ] :skip Optional number of documents to skip. @option options [ Integer ] :limit Optional number of documents to

limit.

@option options [ Array ] :sort Optional sorting options.

@return [ Criteria ] A scoped criteria.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 157
def scoped(options = nil)
  queryable.scoped(options)
end
scopes() click to toggle source

Returns a hash of all the scopes defined for this class, including scopes defined on ancestor classes.

@example Get the defined scopes for a class

class Band
  include Mongoid::Document
  field :active, type: Boolean

  scope :active, where(active: true)
end
Band.scopes

@return [ Hash ] The scopes defined for this class

@since 3.1.4

# File lib/mongoid/scoping.rb, line 31
def scopes
  defined_scopes = {}
  ancestors.reverse.each do |klass|
    if klass.respond_to?(:_declared_scopes)
      defined_scopes.merge!(klass._declared_scopes)
    end
  end
  defined_scopes.freeze
end
unscoped() { |self| ... } click to toggle source

Get the criteria without the default scoping applied.

@example Get the unscoped criteria.

Band.unscoped

@example Yield to block with no default scoping.

Band.unscoped do
  Band.where(name: "Depeche Mode")
end

@note This will force the default scope to be removed.

@return [ Criteria, Object ] The unscoped criteria or result of the

block.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 177
def unscoped
  if block_given?
    without_default_scope do
      yield(self)
    end
  else
    queryable.unscoped
  end
end
with_default_scope() click to toggle source

Get a criteria with the default scope applied, if possible.

@example Get a criteria with the default scope.

Model.with_default_scope

@return [ Criteria ] The criteria.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 195
def with_default_scope
  queryable.with_default_scope
end
Also aliased as: criteria
with_scope(criteria) { |criteria| ... } click to toggle source

Pushes the provided criteria onto the scope stack, and removes it after the provided block is yielded.

@example Yield to the criteria.

Person.with_scope(criteria)

@param [ Criteria ] criteria The criteria to apply.

@return [ Criteria ] The yielded criteria.

@since 1.0.0

# File lib/mongoid/scoping.rb, line 211
def with_scope(criteria)
  scope_stack.push(criteria)
  begin
    yield criteria
  ensure
    scope_stack.pop
  end
end
without_default_scope() { || ... } click to toggle source

Execute the block without applying the default scope.

@example Execute without the default scope.

Band.without_default_scope do
  Band.where(name: "Depeche Mode")
end

@return [ Object ] The result of the block.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 230
def without_default_scope
  Threaded.begin_execution("without_default_scope")
  yield
ensure
  Threaded.exit_execution("without_default_scope")
end

Private Instance Methods

check_scope_name(name) click to toggle source

Warns or raises exception if overriding another scope or method.

@api private

@example Warn or raise error if name exists.

Model.valid_scope_name?("test")

@param [ String, Symbol ] name The name of the scope.

@raise [ Errors::ScopeOverwrite ] If the name exists and configured to

raise the error.

@since 2.1.0

# File lib/mongoid/scoping.rb, line 252
def check_scope_name(name)
  if _declared_scopes[name] || respond_to?(name, true)
    if Mongoid.scope_overwrite_exception
      raise Errors::ScopeOverwrite.new(self.name, name)
    else
      if Mongoid.logger
        Mongoid.logger.warn(
          "Creating scope :#{name}. " +
          "Overwriting existing method #{self.name}.#{name}."
        )
      end
    end
  end
end
check_scope_validity(value) click to toggle source

Checks if the intended scope is a valid object, either a criteria or proc with a criteria.

@api private

@example Check if the scope is valid.

Model.check_scope_validity({})

@param [ Object ] value The intended scope.

@raise [ Errors::InvalidScope ] If the scope is not a valid object.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 280
def check_scope_validity(value)
  unless value.respond_to?(:to_proc)
    raise Errors::InvalidScope.new(self, value)
  end
end
define_scope_method(name) click to toggle source

Defines the actual class method that will execute the scope when called.

@api private

@example Define the scope class method.

Model.define_scope_method(:active)

@param [ Symbol ] name The method/scope name.

@return [ Method ] The defined method.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 299
      def define_scope_method(name)
        (class << self; self; end).class_eval "          def #{name}(*args)
            scoping = _declared_scopes[:#{name}]
            scope, extension = scoping[:scope][*args], scoping[:extension]
            criteria = with_default_scope.merge(scope || all)
            criteria.extend(extension)
            criteria
          end
", __FILE__, __LINE__ + 1
      end
process_default_scope(value) click to toggle source

Process the default scope value. If one already exists, we merge the new one into the old one.

@api private

@example Process the default scope.

Model.process_default_scope(value)

@param [ Criteria, Proc ] value The default scope value.

@since 3.0.5

# File lib/mongoid/scoping.rb, line 322
def process_default_scope(value)
  if existing = default_scoping
    ->{ existing.call.merge(value.to_proc.call) }
  else
    value.to_proc
  end
end
strip_default_scope(value) click to toggle source

Strip the default scope from the provided value, if it is a criteria. This is used by named scopes - they should not have the default scoping applied to them.

@api private

@example Strip the default scope.

Model.strip_default_scope

@param [ Proc, Criteria ] value The value to strip from.

@return [ Proc ] The stripped criteria, as a proc.

@since 3.0.0

# File lib/mongoid/scoping.rb, line 344
def strip_default_scope(value)
  if value.is_a?(Criteria)
    default = default_scoping.try(:call)
    value.remove_scoping(default)
    value.to_proc
  else
    value
  end
end