2012-09-20 5 views
30

これは簡単な質問かもしれませんが、私はここで優雅な解決法を見つけるために私の頭を引っ張っているようです。理想的に頼ることなく、クエリーでnil has_oneの関連付けを検索する

class Item < ActiveRecord::Base 
    has_one :purchase 
end 

class Purchase < ActiveRecord::Base 
    belongs_to :item 
end 

私は、すべてのアイテムのオブジェクトを見つけるためのエレガントな方法を探しています、それに関連付けられた購入オブジェクトを持っていない:私はそれらの間にhas_oneとbelongs_toの関連で、2つのActiveRecordのモデルクラスを持っていますブール値is_purchasedまたは類似の属性を持つアイテムです。

は、今私が持っている:

それは2つのクエリを実行しています(と購入は大規模なレコードセットすることができる)として、機能しますが、私には非効率です
purchases = Purchase.all 
Item.where('id not in (?)', purchases.map(&:item_id)) 

実行のRails 3.1.0

答えて

33

これはかなり一般的なタスクですが、SQL OUTERは、通常はそれのために正常に動作し、JOIN。例えば、hereを見てください。最初の例は、「参照」句を使用せずに動作しますが、

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

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

技術的には4つのスピットをレール:あなたの場合

は、これを行うの

not_purchased_items = Item.joins("LEFT OUTER JOIN purchases ON purchases.item_id = items.id").where("purchases.id IS null") 
+1

このリンクは完璧です!参加は私が必要としていたものとほぼ同じですが、上記のどこを '(purchases.item_idがnullです)'と置き換えなければなりません。ありがとう! –

+0

'has_many'または' has_one'を使用している場合、 'Item.join(:purchases) 'を使って実際のクエリを書く必要なしに結合を達成することができます –

21

見つかり二つの他のrailseyの方法のようなものを使用するようにしてくださいそれがないと廃止予定の警告が表示されます。

+0

これは受け入れられた回答よりも簡潔ですが、関連するテーブルから削除します。あなたのSQLクエリを素敵できちんとした状態に保つには、代わりに@dimuchが提案するカスタム結合を使用してください。 – deadwards

+0

@deadwards私はそれが本当だとは思わない。 AS ID t0_r0、... "添付ファイル"。 "updated_at" AS t1_r7 FROM "assets"。 "Asset.includes(:attachments).where(添付ファイル:{id:nil} LEFT OUTER JOIN "attachments" ON "attachments"。 "property_id" = "assets"。 "property_id" WHERE "attachments"。 "id"はNULLです。@ dimuchの例と同じです。 – bronson

+0

Rails 4 way: 'Item.includes(:purchases).references(:purchases).where(購入:{id:nil})'です。あなたがto_sqlを呼び出すと、すべてのデータが確実にロードされないことがわかります。それは受け入れられた答えとまったく同じことをします。 – bronson

3

@dimuch溶液のより簡潔なバージョンがレール5に導入left_outer_joins方法を使用することである:left_outer_joinsコール:purchaseに特異であること

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

注を(それにより作成されたメソッドの名前でありますhas_one宣言)、where:purchasesには複数(ここではidフィールドが属するテーブルの名前です)

+1

Railsのバージョンを指定できますか?私はこれが> 5であると信じています。 – niborg

+0

ありがとうございます@niborg。それは良いアイデアです。 – ReggieB

関連する問題