web-dev-qa-db-ja.com

Rails 3でスコープを無効にすることは可能ですか?

私のクラスにはCollectionというスコープがあります。

scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)

走れる Collection.with_missing_coins.countそして結果を取得します-うまくいきます!現在、コインを逃さずにコレクションを取得したい場合は、別のスコープを追加します。

scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)

私はこれらの "反対の"スコープをたくさん書いています。可読性を犠牲にすることなく、またはラムダ/メソッド(trueまたはfalseをパラメーターとして取る)に頼ることなく、反対のスコープを取得することは可能ですか?

このようなもの:

Collection.!with_missing_coins
34
Yuval Karmi

これには1つのスコープではなく、2つのスコープを使用します。

scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)

このようにして、これらのスコープが使用されると、何が起こっているかが明確になります。 numbers1311407が示唆していることから、with_missing_coinsfalse引数が何を行っているかはすぐにはわかりません。

できる限り明確にコードを記述し、それがDRYについて熱狂的であることが少なくなることを意味する場合は、たまにそうする必要があります。

14
Ryan Bigg

Rails 4.2では、次のことができます:

scope :original, -> { ... original scope definition ... }
scope :not_original, -> { where.not(id: original) }

サブクエリを使用します。

67
Bill Lipa

ラムダメソッドに頼ることは問題ではないと思いますが、スコープ自体の「逆転」はありません。

scope :missing_coins, lambda {|status| 
  joins(:coins).where("coins.is_missing = ?", status) 
}

# you could still implement your other scopes, but using the first
scope :with_missing_coins,    lambda { missing_coins(true) }
scope :without_missing_coins, lambda { missing_coins(false) }

次に:

Collection.with_missing_coins
Collection.without_missing_coins
7
numbers1311407

これはうまくいくかもしれませんが、あまりテストしていません。 Rails 5を使用すると思いますRails 3にはwhere_clauseの代わりにwhere_valuesメソッドがあります。

_
scope :not, ->(scope_name) do 
              query = self
              send(scope_name).joins_values.each do |join|
                   query = query.joins(join)
              end
              query.where((send(scope_name).
                    where_clause.send(:predicates).reduce(:and).not))
end
_

使用法

Model.not(:scope_name)

0
Harsimar Sandhu