Supposons que vous ayez besoin d'obtenir le nom d'utilisateur des cinq premiers messages. Vous écrivez rapidement la requête ci-dessous et allez profiter de votre week-end.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Bien. Mais regardons les requêtes
Post Load (0.5ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
1 query
pour récupérer tous les posts
et 1 query
pour récupérer les users
pour chaque message, cela donne un total de 6 queries
. Découvrez la solution ci-dessous qui fait la même chose, juste en 2 queries
:
posts = Post.includes(:user).limit(5)
posts.each do |post|
puts post.user.name
end
#####
Post Load (0.3ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2)
Il y a une petite différence. Ajouter includes(:posts)
à votre requête, et problème résolu. Rapide, agréable et facile.
Mais ne vous contentez pas d'ajouter includes
dans votre requête sans bien la comprendre. Utiliser includes
avec joins
peut entraîner des jointures croisées selon la situation, et vous n'en avez pas besoin dans la plupart des cas.
Si vous souhaitez ajouter des conditions à vos modèles inclus, vous devrez les référencer explicitement . Par exemple :
User.includes(:posts).where('posts.name = ?', 'example')
Lancera une erreur, mais cela fonctionnera :
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Notez que includes
fonctionne avec les association names
tandis que les references
nécessite the actual table name
.