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
.