Předpokládejme, že potřebujete získat uživatelské jméno prvních pěti příspěvků. Rychle napište dotaz níže a jděte si užít víkend.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Dobrý. Ale podívejme se na dotazy
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 pro načtení všech posts a 1 query k načtení users pro každý příspěvek vygeneruje celkem 6 queries . Podívejte se na níže uvedené řešení, které dělá totéž, jen ve 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)
Je tu jeden malý rozdíl. Přidejte includes(:posts) na váš dotaz a problém vyřešen. Rychlé, pěkné a snadné.
Nepřidávejte však pouze includes ve vašem dotazu, aniž byste mu správně rozuměli. Použití includes s joins může v závislosti na situaci vést ke křížovým spojům a to ve většině případů nepotřebujete.
Pokud chcete k zahrnutým modelům přidat podmínky, musíte na ně výslovně odkazovat . Například:
User.includes(:posts).where('posts.name = ?', 'example')
Vyvolá chybu, ale bude to fungovat:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Všimněte si, že includes pracuje s association names zatímco references potřebuje the actual table name .