2017-10-19 11 views
0

Laissez-moi vous expliquer le titre.Rails 5 - ActiveRecord - Filtrage has_many relation avec includes et ne pas exclure les valeurs vides

J'ai modèle A ce modèle has_many B.

Je veux filtrer le modèle B par mois et l'année de la date tout en montrant tous les modèles A de

donc par exemple:

A1 -> 3 hôtes

A2 -> 0 B

A3 -> 1 B

Ceci est ma requête en ce moment:

A.includes(:b_relation) 
.where("extract(month from b.date) = #{month}").references(:b_relation) 
.where("extract(year from b.date) = #{year}").references(:b_relation) 
.all 

Il fonctionne! MAIS cela me donne seulement le A qui a au moins un B. Les A qui n'en ont pas ne le montrent pas.

Comment faire pour que la requête inclue les modèles A qui n'ont pas de B?

Répondre

1

La requête que vous faites actuellement utilise un INNER JOIN qui exclura les enregistrements de A qui n'ont aucun B s associé. Ce que vous voulez à la place est un LEFT OUTER JOIN -aka un LEFT JOIN. Les jointures à gauche incluent toutes les lignes de la table parent, qu'il y ait ou non des enregistrements associés dans la table associée.

Je trouve toujours cette image utile pour visualiser SQL types de jointure:

enter image description here

Rails 5 a une left_outer_joinsmethod pour ce (alias: left_joins):

A.left_outer_joins(:b_relation) 

Dans les versions antérieures de Rails, c'est plus manuel (je fais juste les noms des tables ici):

A.joins('LEFT OUTER JOIN "bs" ON "bs"."a_id" = "as"."id"') 
+0

Si je regarde ma requête exécutée, elle fait un LEFT OUTER JOIN parce qu'inclut en interne va décider d'utiliser la méthode ActiveRecord 'eager_load'. Il utilise déjà LEFT OUTER JOIN – Lokuzt

+0

Pouvez-vous partager le SQL généré par votre requête AR? – hoffm

+0

Quelque chose comme ce SELECT "A" "id" AS t0_r0, -.. A COLONNES "B" "id" AS t1_r0, - B COLONNES de "A" LEFT OUTER JOIN "B" ON "B". "a_id" = "A". "id" où "A". "deleted_at" IS NULL \t ET "A". "blabla_id" = 'cfa7e8a8-5566-4ce7-bcbc-05cf420cf7d1' AND ((Extrait (mois FROM B.date) = 10) \t AND (Extrait (année à partir de B.date) = 2017) OU B.date IS NULL) – Lokuzt