J'ai le code suivant:
@posts = Post.joins(:user).joins(:blog).select
qui est destiné à trouver tous les messages et à les renvoyer ainsi qu'aux utilisateurs et blogs associés. Cependant, les utilisateurs sont facultatifs, ce qui signifie que le INNER JOIN
cette :joins
génère ne renvoie pas beaucoup d'enregistrements.
Comment puis-je l'utiliser pour générer un LEFT OUTER JOIN
au lieu?
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").
joins(:blog).select
Vous pouvez le faire avec includes
comme indiqué dans le guide Rails :
Post.includes(:comments).where(comments: {visible: true})
Résulte en:
SELECT "posts"."id" AS t0_r0, ...
"comments"."updated_at" AS t1_r5
FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
WHERE (comments.visible = 1)
Je suis un grand fan de la gemme squeel :
Post.joins{user.outer}.joins{blog}
Il prend en charge les jointures inner
et outer
, ainsi que la possibilité de spécifier une classe/type pour les relations d'appartenance polymorphe.
Utilisation eager_load
:
@posts = Post.eager_load(:user)
Par défaut, lorsque vous passez ActiveRecord::Base#joins
une association nommée, elle effectuera une INNER JOIN. Vous devrez passer une chaîne représentant votre jointure extérieure gauche.
De la documentation :
:joins
- Soit un fragment SQL pour des jointures supplémentaires comme "LEFT JOIN comments ON comments.post_id = id
"(rarement nécessaire), associations nommées sous la même forme utilisée pour le:include
option, qui effectuera une INNER JOIN sur les tables associées, ou un tableau contenant un mélange de chaînes et d'associations nommées.Si la valeur est une chaîne, les enregistrements seront renvoyés en lecture seule, car ils auront des attributs qui ne correspondent pas aux colonnes de la table. Passer
:readonly => false
pour remplacer.
Il existe une méthode left_outer_joins dans activerecord. Vous pouvez l'utiliser comme ceci:
@posts = Post.left_outer_joins(:user).joins(:blog).select
Bonne nouvelle, Rails 5 prend désormais en charge LEFT OUTER JOIN
. Votre requête ressemblerait maintenant à:
@posts = Post.left_outer_joins(:user, :blog)
class User < ActiveRecord::Base
has_many :friends, :foreign_key=>"u_from",:class_name=>"Friend"
end
class Friend < ActiveRecord::Base
belongs_to :user
end
friends = user.friends.where(:u_req_status=>2).joins("LEFT OUTER JOIN users ON users.u_id = friends.u_to").select("friend_id,u_from,u_to,u_first_name,u_last_name,u_email,u_fbid,u_twtid,u_picture_url,u_quote")