How to union two different Mongoid Criteria
You can try to compose your criteria using Mongoid's query methods and dereferencing into the criteria's selector, but I wouldn't necessarily recommend this -- see below for an example. I second the recommendation to craft your third scope. Remember that these scopes correspond to db queries that you want to be efficient, so it is probably worth your time to examine and understand the resulting and underlying MongoDB queries that are generated.
Model
class Episode include Mongoid::Document field :name, type: String field :start_time, type: Time field :end_time, type: Time scope :upcoming, -> { where(:start_time.gt => Time.now).asc(:start_time) } scope :in_progress, -> { now = Time.now where(:start_time.lte => now).where(:end_time.gte => now).asc(:start_time) } scope :current, -> { any_of([upcoming.selector, in_progress.selector]) } scope :current_simpler, -> { where(:end_time.gte => Time.now) }end
Test
require 'test_helper'class EpisodeTest < ActiveSupport::TestCase def setup Episode.delete_all end test "scope composition" do #p Episode.in_progress #p Episode.upcoming #p Episode.current #p Episode.current_simpler in_progress_name = 'In Progress' upcoming_name = 'Upcoming' Episode.create(:name => in_progress_name, :start_time => Time.now, :end_time => 1.hour.from_now) Episode.create(:name => upcoming_name, :start_time => 1.hour.from_now, :end_time => 2.hours.from_now) assert_equal([in_progress_name], Episode.in_progress.to_a.map(&:name)) assert_equal([upcoming_name], Episode.upcoming.to_a.map(&:name)) assert_equal([in_progress_name, upcoming_name], Episode.current.to_a.map(&:name)) assert_equal([in_progress_name, upcoming_name], Episode.current_simpler.to_a.map(&:name)) endend
You have to map your Array back to a Mongoid::Criteria.Any array of yours can be translated to a criteria with any_in:
scope :has_data, -> { any_in(:_id => all.select{ |record| record.data.size > 0 }.map{ |r| r.id }) }
So, something like this should do the trick: (untested)
scope :current, -> { any_in(:_id => (self.in_progress + self.upcoming).map{ |r| r.id }) }
I hope there exists better solutions, but this solves the equation at least.