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 .