Supponiamo di dover ottenere il nome utente dei primi cinque post. Scrivi rapidamente la domanda qui sotto e vai a goderti il tuo fine settimana.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Bene. Ma diamo un'occhiata alle query
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 per recuperare tutti i posts e 1 query per recuperare users per ogni post risulta un totale di 6 queries . Dai un'occhiata alla soluzione di seguito che fa la stessa cosa, solo 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)
C'è una piccola differenza. Aggiungi includes(:posts) alla tua domanda e problema risolto. Veloce, piacevole e facile.
Ma non limitarti ad aggiungere includes nella tua query senza capirla correttamente. L'utilizzo di includes con joins potrebbe comportare collegamenti incrociati a seconda della situazione e nella maggior parte dei casi non è necessario.
Se vuoi aggiungere condizioni ai tuoi modelli inclusi, dovrai farne esplicito riferimento . Ad esempio:
User.includes(:posts).where('posts.name = ?', 'example')
Verrà generato un errore, ma funzionerà:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Nota che includes funziona con association names mentre references richiede the actual table name .