Antag, at du skal have brugernavnet til de første fem indlæg. Du skriver hurtigt nedenstående forespørgsel og nyd din weekend.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Godt. Men lad os se på forespørgslerne
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
for at hente alle posts
og 1 query
for at hente users
for hvert indlæg resulterer i i alt 6 queries
. Tjek løsningen nedenfor, som gør det samme, bare i 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)
Der er en lille forskel. Tilføj includes(:posts)
til din forespørgsel, og problemet løst. Hurtigt, godt og nemt.
Men du skal ikke bare tilføje includes
i din forespørgsel uden at forstå den ordentligt. Brug af includes
med joins
kan resultere i krydsforbindelser afhængigt af situationen, og det behøver du ikke i de fleste tilfælde.
Hvis du vil tilføje betingelser til dine inkluderede modeller, skal du udtrykkeligt henvise til dem . For eksempel:
User.includes(:posts).where('posts.name = ?', 'example')
Vil give en fejl, men dette vil virke:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Bemærk, at includes
fungerer med association names
mens references
skal bruge the actual table name
.