は、カテゴリ名または指定した文字列に一致する作物名のいずれかでフィルタ、その後、両方の彼らのカテゴリへと、そのカテゴリに関連付けられている作物へのすべての寄付に参加しています。そのSQLでやって起動してみましょう:
SELECT d.*
FROM donations d
JOIN categories ca ON ca.id = d.category_id
JOIN categories_crops cc ON cc.category_id = ca.id
JOIN crops cr ON cr.id = cc.crop_id
WHERE
ca.name LIKE 'foo%'
OR
cr.name LIKE 'foo%'
だからあなたのデータセットは以下のように見えるとします
donations categories crops categories_crops
---------------- ------------------ ------------ ---------------------
id | category_id id | name id | name crop_id | category_id
================ ================== ============ =====================
1 | 1 1 | leafy greens 1 | lettuce 1 | 1
2 | 1 2 | dark greens 2 | broccoli 2 | 2
3 | 2 3 | kale 3 | 1
3 | 2
ザ・はスリムダウン、次のようになります事前にフィルタ処理セットが生成されます上記のJOIN簡単に表現するために:あなたが見ることができるように
donations X categories X categories_crops X crops
-------------------------------------------------
donation_id | category.name | crops.name
=================================================
1 | leafy greens | lettuce
1 | leafy greens | kale
2 | leafy greens | lettuce
2 | leafy greens | kale
3 | dark greens | broccoli
3 | dark greens | kale
、各寄付IDは、この時点で、私はSUないよ、ということに注意してください(に寄付カテゴリの下にあったすべての作物の横に表示されますデータモデルが正しいか間違っているかどうかいずれにしても、私が描いている原則はあなたと他の人を助けるはずです。我々は緑豊かなによってフィルタリングのであれば、我々はすべてが理にかなっていることをうまくいけば、我々はケールによってフィルタする場合、我々は寄付金1を取り戻すだろう寄付1と2を取り戻す2、および3
たい最後にSQLをActiveRecordに変換することができます。それはかなり直接的です:
Donations
.joins(category: :crops)
.where('categories.name LIKE :term OR crops.name LIKE :term', term: "%#{search_term}%")
join
は正確にあなたの関係が設定されている方法に応じて、category: { categories_crops: :crops })
、または何か他のものをする必要があります。アイデアは、上記のような結合を構築するために定義した関係をトラバースすることです。
は
EDIT: - >カテゴリ関係なく、同じ名前のカテゴリの作物名に置き換えコメントでパーOPの明確化は、データモデルは、作物から推測されるカテゴリの暗黙の階層が含まれています。追加のロジックが必要だがデータベース設計から明らかにならない暗黙の関係は、クエリするのが難しい場合があります。データモデルが更新する必要がある場合が多いということがよくあります。しかし、まずクエリを更新してみましょう。
検索対象のカテゴリに「属し」ているカテゴリも含める必要があります。追加する必要があります。すべてのカテゴリに親カテゴリがあるわけではないため、外部結合である必要があります。しかし、参加条件は変わってきます。私の最初の考えは、親カテゴリの名前にカテゴリを結合する一時テーブルを作成し、その上に結合するだけです。だから、クエリは次のようになります。レールに翻訳
SELECT d.*
FROM donations d
JOIN categories ca ON ca.id = d.category_id
JOIN categories_crops cc ON cc.category_id = ca.id
JOIN crops cr ON cr.id = cc.crop_id
LEFT JOIN (
SELECT ca2.name as parent_category_name, ca3.id as child_category_id
FROM categories_crops cc2
JOIN categories ca2 ON ca2.id = cc2.category_id
JOIN crops cr2 ON cr2.id = cc2.crop_id
JOIN categories ca3 ON ca3.name = cr2.name
) cp
ON cp.child_category_id = ca.id
WHERE
ca.name LIKE 'foo%'
OR
cr.name LIKE 'foo%'
OR
cp.parent_category_name LIKE 'foo%'
:応答のための
Donations
.joins(category: :crops)
.joins(<<-SQL)
LEFT JOIN (
SELECT ca2.name as parent_category_name, ca3.category_id as child_category_id
FROM categories_crops cc2
JOIN categories ca2 ON ca2.id = cc2.category_id
JOIN crops cr2 ON cr2.id = cc2.crop_id
JOIN categories ca3 ON ca3.name = cr2.name
) cp ON cp.child_category_id = categories.id
SQL
.where('categories.name LIKE :term OR crops.name LIKE :term OR cp.parent_category_name LIKE :term', term: "%#{search_term}%")
ありがとう!これは検索用語が** kale **の場合に役立つようです** kale **と** leafy green **の両方の項目を取得しますが、** leafy green ** **はまだ** leafy green **エントリー。 – Bevilacqua
@Bevilacquaあなたは、そのシナリオでどんなことを期待しているかについて詳しく説明できますか?なぜ「葉っぱの緑」の検索が「レタス」と「ケール」以上に戻ってくるのかわからない。 –
これは実際には私が返すものですが、現在はリーフグリーンで明示的にマークされたエントリのみを返します。 Ex。カテゴリ:[lettuce]、[kale]、[leefy greens]の3つのエントリが寄付されている場合。私は葉緑色のエントリだけを取得します。 – Bevilacqua