41

これは簡単な質問かもしれませんが、私はここでエレガントな解決策を見つけるために髪を引っ張っているようです。2つのActiveRecordモデルクラスがあり、それらの間にhas_oneとbelongs_toの関連付けがあります。

class Item < ActiveRecord::Base
  has_one :purchase
end

class Purchase < ActiveRecord::Base
  belongs_to :item
end

購入オブジェクトが関連付けられていないすべてのアイテムオブジェクトを見つけるためのエレガントな方法を探しています。理想的is_purchasedには、アイテムにブール値または同様の属性を設定する必要はありません。

今私は持っています:

purchases = Purchase.all
Item.where('id not in (?)', purchases.map(&:item_id))

これは機能しますが、2つのクエリを実行しているため、私には非効率に思えます(そして、購入は膨大なレコードセットになる可能性があります)。

ランニングレール3.1.0

4

4 に答える 4

38

これは非常に一般的なタスクであり、SQLOUTERJOINは通常正常に機能します。たとえば、ここを見てください。

あなたの場合、次のようなものを使用してみてください

not_purchased_items = Item.joins("LEFT OUTER JOIN purchases ON purchases.item_id = items.id").where("purchases.id IS null")
于 2012-09-20T15:12:19.577 に答える
33

これを行う他の2つの鉄道の方法を見つけました:

Item.includes(:purchase).references(:purchase).where("purchases.id IS NULL")

Item.includes(:purchase).where(purchases: { id: nil })

技術的には、最初の例は「references」句なしで機能しますが、Rails4はそれなしで非推奨の警告を出します。

于 2013-11-06T19:15:52.080 に答える
16

@dimuchソリューションのより簡潔なバージョンは、Rails5でleft_outer_joins導入された方法を使用することです。

Item.left_outer_joins(:purchase).where(purchases: {id: nil})

left_outer_joins呼び出し:purchaseでは単数形(has_one宣言によって作成されたメソッドの名前)であり、where句では複数形(ここではフィールドが属する:purchasesテーブルの名前です)であることに注意してください。id

于 2018-01-30T08:56:39.033 に答える
1

missingRails 6.1には、ActiveRecord::QueryMethods::WhereChainクラスで呼び出されるクエリメソッドが追加されています。

左外部結合と親モデルと子モデルの間のwhere句を使用して新しい関係を返し、欠落している関係を識別します。

例:

Item.where.missing(:purchase)
于 2021-09-30T09:14:37.960 に答える