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 .