web-dev-qa-db-ja.com

空のActiveRecordリレーションを返す方法は?

ラムダを持つスコープがあり、引数の値に応じて引数を取る場合、一致するものはないことを知っているかもしれませんが、空の配列ではなくリレーションを返したいです:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }

私が本当に欲しいのは、「all」の反対の「none」メソッドです。このメソッドは、連鎖することができるリレーションを返しますが、クエリは短絡します。

230
dzajic

Rails 4には「正しい」メカニズムがあります:

>> Model.none 
=> #<ActiveRecord::Relation []>
443
steveh7

「id」列を必要とせず、idが0の行がないことを前提としない、より移植性の高いソリューション:

scope :none, where("1 = 0")

もっと「正しい」方法を探しています。

75
steveh7

Rails 4で登場

Rails 4では、ActiveRecord::NullRelationなどの呼び出しからチェーン可能なPost.noneが返されます。

それも、連鎖メソッドも、データベースへのクエリを生成しません。

コメントによると:

返されるActiveRecord :: NullRelationは、Relationを継承し、Null Objectパターンを実装します。 null動作が定義されたオブジェクトであり、データベースをクエリせずに常にレコードの空の配列を返します。

ソースコード を参照してください。

43
Nathan Long

「none」というスコープを追加できます。

scope :none, where(:id => nil).where("id IS NOT ?", nil)

空のActiveRecord :: Relationが得られます

また、初期化子のActiveRecord :: Baseに追加することもできます(必要な場合)。

class ActiveRecord::Base
 def self.none
   where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
 end
end

このようなものを手に入れる方法はたくさんありますが、コードベースに保管するのが最善ではありません。空のActiveRecord :: Relationを短時間保証する必要があることをリファクタリングして見つけるときに、スコープ:noneを使用しました。

42
Brandon
scope :none, limit(0)

スコープが連鎖している可能性があるため、危険なソリューションです。

User.none.first

最初のユーザーを返します。使用する方が安全です

scope :none, where('1 = 0')
24
bbrinck

私はこれが他のオプションに見える方法を好むと思う:

scope :none, limit(0)

このようなものにつながる:

scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }
14
Alex

スコープを使用:

 scope:for_users、lambda {| users | users.any? ? where( "user_id IN(?)"、users.map(&:id).join( '、')):スコープ} 

ただし、次の方法でコードを簡素化することもできます。

 scope:for_users、lambda {| users | where(:user_id => users.map(&:id))if users.any? } 

空の結果が必要な場合は、これを使用します(if条件を削除します):

 scope:for_users、lambda {| users | where(:user_id => users.map(&:id))} 
3
Pan Thomakos

それは可能ですので、それは:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : User.none }

http://apidock.com/Rails/v4.0.2/ActiveRecord/QueryMethods/none

私が間違っている場合は修正してください。

1
ilgam

バリアントもありますが、これらはすべてdbにリクエストを送信しています

where('false')
where('null')
1
fmnoise