How do you set up chainable scopes based on relations in Mongoid

Although @MZaragoza's answer was complete, it seems that this syntax is no longer allowed:

scope :rock_n_rolla, where(occupation: "Rockstar")

Use procs instead:

summary:
  Scopes in Mongoid must be procs that wrap criteria objects.
resolution:
  Change the scope to be a proc wrapped critera.

 Example:
   class Band
     include Mongoid::Document
     scope :inactive, ->{ where(active: false) }
   end

Mongoid v 7.0.3


scopes

Similar to Active Record, Mongoid allows you to define scopes on your models as a convenience for filtering result sets. Scopes are defined at the class level, either using the scope macro or by defining class methods that return a criteria object. All scopes are chainable and can be applied to associations as well, the later being discussed in the relations section.

Named scopes are defined at the class level using a scope macro and can be chained to create result sets in a nice DSL.

class Person
  include Mongoid::Document
  field :occupation, type: String
  field :age, type: Integer

  scope :rock_n_rolla, where(occupation: "Rockstar")
  scope :washed_up, where(:age.gt => 30)
  scope :over, ->(limit) { where(:age.gt => limit) }
end

# Find all the rockstars.
Person.rock_n_rolla

# Find all rockstars that should probably quit.
Person.washed_up.rock_n_rolla

# Find a criteria with Keith Richards in it.
Person.rock_n_rolla.over(60)

Note that definitions are evaluated at class load time. For evaluation at runtime you will want to make sure to define using a proc or lambda. In the following example the first date is set as the date of class load, where the second scope sets the date at the time the scope is called.

scope :current, where(:start_date.lte => Date.today)
scope :current, -> { where(:start_date.lte => Date.today) }

class methods

For those who prefer a Data Mapper style syntax, class methods that return criteria can be treated as chainable scopes as well.

class Person
  include Mongoid::Document
  field :occupation, type: String
  field :age, type: Integer

  class << self

    def rock_n_rolla
      where(occupation: "Rockstar")
    end

    def washed_up
      where(:age.gt => 30)
    end

    def over(limit)
      where(:age.gt => limit)
    end
  end
end

# Find all the rockstars.
Person.rock_n_rolla

# Find all rockstars that should probably quit.
Person.washed_up.rock_n_rolla

# Find a criteria with Keith Richards in it.
Person.rock_n_rolla.over(60)

Named scopes and class methods that return a criteria can be chained together - that's the beauty of Mongoid's powerful criteria API.

class Person
  include Mongoid::Document
  field :occupation, type: String
  field :age, type: Integer

  scope :washed_up, where(:age.gt => 30)
  scope :over, ->(limit) { where(:age.gt => limit) }

  def self.rock_n_rolla
    where(occupation: "Rockstar")
  end
end

# Same queries apply here as well.
Person.rock_n_rolla
Person.washed_up.rock_n_rolla
Person.rock_n_rolla.over(60)