Stel dat u de gebruikersnaam van de eerste vijf berichten moet krijgen. Je schrijft snel onderstaande vraag en gaat genieten van je weekend.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Mooi zo. Maar laten we eens kijken naar de vragen
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 om alle posts op te halen en 1 query om users op te halen voor elk bericht resulteert in een totaal van 6 queries . Bekijk de onderstaande oplossing die hetzelfde doet, alleen in 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)
Er is één klein verschil. Voeg includes(:posts) toe op uw vraag, en probleem opgelost. Snel, leuk en gemakkelijk.
Maar voeg niet alleen includes toe in uw vraag zonder het goed te begrijpen. Het gebruik van includes met joins kan resulteren in cross-joins, afhankelijk van de situatie, en dat heb je in de meeste gevallen niet nodig.
Als u voorwaarden wilt toevoegen aan uw opgenomen modellen, moet u hier expliciet naar verwijzen . Bijvoorbeeld:
User.includes(:posts).where('posts.name = ?', 'example')
Zal een foutmelding geven, maar dit zal werken:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Merk op dat includes werkt met association names terwijl references heeft the actual table name nodig .