9

モデルで次のスコープが定義されています。

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, -> { self.in_progress | self.upcoming }

しかし、これは両方を配列のように扱い、それらを連結するだけです。これの問題は、Model.current でスコープを呼び出そうとすると、次のエラー メッセージが表示されることです。

NoMethodError: undefined method `as_conditions' for #<Array:0xaceb008>

これは、Mongoid Criteria オブジェクトを配列に変換したためですが、私はそれを望んでいません。オブジェクトを Mongoid Criteria オブジェクトのままにしたい。

私が本当に欲しいのは、in_progress セットと次のセットの結合です。

何か案は?ありがとう。

4

2 に答える 2

7

Mongoid のクエリ メソッドを使用して基準を構成し、基準のセレクターに逆参照することもできますが、これは必ずしもお勧めしません。以下の例を参照してください。3 番目のスコープを作成することをお勧めします。これらのスコープは、効率的にしたい db クエリに対応していることに注意してください。そのため、生成された結果および基になる 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
于 2012-04-23T21:07:13.300 に答える
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 }) }

より良い解決策が存在することを願っていますが、これは少なくとも方程式を解決します。

于 2012-05-05T16:20:16.287 に答える