has_manyに複数の関連付けが存在するかどうかを確認することはできますか?この場合、「a」、「b」、「c」の3つのタグが付いた本があるかどうかを確認したいと思います。
(本とタグは多対多で関連付けられています。)
if Book.all.tags.find("a", "b", "c").any?
# Yay!
# There is at least one book with all three tags (a, b & c)
end
has_manyに複数の関連付けが存在するかどうかを確認することはできますか?この場合、「a」、「b」、「c」の3つのタグが付いた本があるかどうかを確認したいと思います。
(本とタグは多対多で関連付けられています。)
if Book.all.tags.find("a", "b", "c").any?
# Yay!
# There is at least one book with all three tags (a, b & c)
end
私はこれがトリックを行うと思います(で動作しますhas_many
):
Book.includes(:tags).where(tags: { name: ['a', 'b', 'c'] }).any?
それを分解する:
Railsに、タグを1つずつ読み込むのincludes
ではなく、積極的な読み込みを使用してタグを読み込むように指示します。これによりtags
、クエリで注意を払い、よりスマートなクエリを生成することもできます。
where
条件は非常に単純で、配列を渡すだけで比較が条件に変換さ=
れIN ('a', 'b', 'c')
ます。
Railsは賢いany?
ので、レコードをロードするのではなく(派手なクエリを生成します)、カウントをロードするだけのレコードを生成します。
私はこのクエリ構造を使用します:
Book
.select('distinct books.*')
.joins(:tags)
.where('tags.slug' => ['a', 'b', 'c'])
.group("pages.id")
.having("count(*) = #{['a', 'b', 'c'].size}")
私はこの問題を解決するためのエレガントなレールの方法を見つけたことがないので、うまくいけば他の誰かがより良い答えを持って来るでしょう。
野蛮な方法はsqlにドロップダウンすることです。これをメモリから書き込んでいるので、構文に問題がある可能性があります。
Bookモデルではこのようなものです。テーブルの短縮名は、親クエリと競合しないようにするためのものです。
def self.with_tag(tag)
where("EXISTS (SELECT 1 from books_tags bt, tags t where bt.tag_id = t.id
and bt.book_id = books.id and t.name = ?)", tag)
end
次に、別のメソッドを呼び出すBook.with_tag('a').with_tag('b').with_tag('c')
か定義します。スコープ変数が必要かどうかわからない。
def self.with_all_tags(tags)
scope = self.scoped
tags.each do |t|
scope = scope.with_tag(t)
end
end