Anta att du behöver få användarnamnet för de fem första inläggen. Du skriver snabbt frågan nedan och njut av helgen.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Bra. Men låt oss titta på frågorna
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
för att hämta alla posts
och 1 query
för att hämta users
för varje inlägg resulterar det i totalt 6 queries
. Kolla in lösningen nedan som gör samma sak, bara 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)
Det är en liten skillnad. Lägg till includes(:posts)
till din fråga och problemet löst. Snabbt, trevligt och enkelt.
Men lägg inte bara till includes
i din fråga utan att förstå den ordentligt. Att använda includes
med joins
kan resultera i korskopplingar beroende på situationen, och det behöver du inte i de flesta fall.
Om du vill lägga till villkor för dina medföljande modeller måste du uttryckligen hänvisa till dem . Till exempel:
User.includes(:posts).where('posts.name = ?', 'example')
Kommer att ge ett fel, men detta kommer att fungera:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Observera att includes
fungerar med association names
medan references
behöver the actual table name
.