3

いくつかの問題モデルに関連するいくつかの製品を含むRailsアプリケーションがあります。これらの製品の中にはissue_id(問題ありhas_manyなど)があり、そうでないものもあります。製品なしの発行IDは私が取り組んでいる新しい追加です。複数の条件付きActiveRecordスコープの作成

私はProduct.publishedを使用して製品を一覧表示することができますように、私が以前にこのようになります。これは、名前のスコープを持っていた:

scope :published, -> { 
    joins(:issue).reorder('products.created_at ASC, products.number ASC') 
    .where('products.status = ?', Product.statuses[:available]) 
    .where('issues.status = ?', Issue.statuses[:published]) 
} 

この結果は、私が公開問題(に関連付けられているだけの製品を見つけることができるということですマガジンの問題を考える)。

私は現在、特定の問題に関連付けられていないが、依然としてドラフト/使用可能な状態の製品を追加しています。上記のスコープでは、存在しないissue_idを検索するため、これらの製品は見つかりません。

私は最後の行でOR issue_id IS NULL一部追加、私はこのような範囲を変更すると考えていた:

scope :published, -> { 
    joins(:issue).reorder('products.created_at ASC, products.number ASC') 
    .where('products.status = ?', Product.statuses[:available]) 
    .where('issues.status = ? OR issue_id IS NULL', Issue.statuses[:published]) 
} 

しかし、これは動作しませんが。私はまだ「公開された」問題に関連する「利用可能な」製品のみを取得します。 issue_idのない製品は、返されたコレクションには含まれません。

(それに関連する問題が公表される前に、私は両方のレコードの状態を確認する必要がありますこのような状況のためのように、製品には、利用可能に設定されるウィンドウがあります。)

ここでSQLです上記(読みやすいように改行)によって生成された:私は頻繁に探していますので、私はすでに別の方法として引数を取りますが、すべてのケースでは動作しませんProductクラスのメソッドを作成しました

pry(main)> Product.published.to_sql 
=> "SELECT `products`.* FROM `products` INNER JOIN `issues` ON `issues`.`id` = 
`products`.`issue_id` WHERE (products.status = 1) AND (issues.status = 1 OR 
issue_id IS NULL) ORDER BY products.created_at ASC, products.number ASC" 

問題提携があるかどうかを事前に知らなくても、IDに基づいた製品rはありません(例:製品の の表示の表示の場合)。 Product.published Product.publishedまた、 Product.publishedは、公開されたすべての製品(例: Product.where(:status => :published))を読み込み、2回目の操作で公開されていない問題に関連するものを削除するために繰り返します。

私はスコープ内でより複雑なクエリを実行することについて十分に把握していないような気がします。私の理想的な結果は、問題の有無にかかわらず、引数を指定せずに利用可能な製品を返すことができる変更されたスコープです。

これは可能ですか、これらの関連していない製品を追加するようになりましたので、私は代わりのアプローチを見つけるために辞任すべきですか?

+0

このクエリで生成されたSQLは、たとえば 'Product.published 'を使って見てください。to_sql'(あなたの質問を編集してそこに結果を追加してみましょう):なぜSQLが間違っているのかを理解して、必要な修正をRubyスコープにバックポートすることができます。 –

+1

良いアイデア@TarynEast、ありがとう。私は以前にチェックした生成されたSQLを追加しましたが、私は実際に結合の周りを頭で覆っていませんでしたので、問題を見る助けにはなりませんでした。 – Kenn

答えて

4

問題はjoins(:issue)を使用していることです。その方法は、productsissuesテーブルの間にINNER JOINを実行し、issue_idを持たないすべての製品を破棄します。たぶんLEFT JOINを使うことができるので、問題があるかどうかに関係なくすべての製品を保管することができます。

scope :published, -> { 
    joins('LEFT JOIN issues ON issues.id = products.issue_id') 
    .select('products.*') 
    .reorder('products.created_at ASC, products.number ASC') 
    .where('products.status = ?', Product.statuses[:available]) 
    .where('issues.status = ? OR products.issue_id IS NULL', Issue.statuses[:published]) 
} 
+0

これは、ありがとう!私は明らかにもっと実際のSQLを学ぶ必要があります。 – Kenn

+0

恐ろしい!私はあなたがそれを動作させることができてうれしいです! –

関連する問題