我的模型中定义了以下范围:
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)
}
我想创建另一个范围,它结合了两个名为current的范围的结果。我试过这样的事情:
scope :current, -> { self.in_progress | self.upcoming }
但这最终会将它们视为数组并将它们连接起来。这个问题是当我尝试使用Model.current调用我的作用域时,我收到以下错误消息:
NoMethodError: undefined method `as_conditions' for #<Array:0xaceb008>
这是因为它将Mongoid Criteria对象转换为数组,但我不希望这样。我希望该对象保留为Mongoid Criteria对象。
我真正想要的是in_progress集合和即将发布的集合。
有什么想法吗?感谢。
答案 0 :(得分:6)
您可以尝试使用Mongoid的查询方法和解除引用到条件的选择器来组成您的条件,但我不一定会建议这样做 - 请参阅下面的示例。我建议你制作第三个范围。请记住,这些范围对应于您希望高效的数据库查询,因此可能值得花时间检查和理解生成的结果和基础MongoDB查询。
模型
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
测试
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))
end
end
答案 1 :(得分:2)
您必须将数组映射回Mongoid :: Criteria。 您的任何数组都可以使用any_in:
转换为条件scope :has_data, -> { any_in(:_id => all.select{ |record| record.data.size > 0 }.map{ |r| r.id }) }
所以,这样的事情可以解决这个问题:(未经测试)
scope :current, -> { any_in(:_id => (self.in_progress + self.upcoming).map{ |r| r.id }) }
我希望有更好的解决方案,但至少可以解决这个问题。