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
.