Suponga que necesita obtener el nombre de usuario de las primeras cinco publicaciones. Escribe rápidamente la consulta a continuación y disfruta de tu fin de semana.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Bien. Pero veamos las consultas
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
para obtener todas las posts
y 1 query
para obtener users
por cada publicación da como resultado un total de 6 queries
. Consulte la solución a continuación que hace lo mismo, solo 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)
Hay una pequeña diferencia. Agregar includes(:posts)
a su consulta, y problema resuelto. Rápido, agradable y fácil.
Pero no se limite a agregar includes
en su consulta sin entenderlo correctamente. Usar includes
con joins
podría resultar en uniones cruzadas dependiendo de la situación, y no es necesario en la mayoría de los casos.
Si desea agregar condiciones a sus modelos incluidos, deberá hacer referencia explícita a ellos . Por ejemplo:
User.includes(:posts).where('posts.name = ?', 'example')
Lanzará un error, pero esto funcionará:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Tenga en cuenta que includes
funciona con association names
mientras references
necesita the actual table name
.