Да предположим, че трябва да получите потребителското име на първите пет публикации. Бързо напишете заявката по-долу и отидете да се насладите на уикенда си.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Добре. Но нека да разгледаме заявките
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
за извличане на всички posts
и 1 query
за извличане на users
за всяка публикация води до общо 6 queries
. Вижте решението по-долу, което прави същото, само в 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)
Има една малка разлика. Добавете includes(:posts)
към вашето запитване и проблемът е решен. Бързо, приятно и лесно.
Но не просто добавяйте includes
във вашето запитване, без да го разбирате правилно. Използване на includes
с joins
може да доведе до кръстосани съединения в зависимост от ситуацията и в повечето случаи нямате нужда от това.
Ако искате да добавите условия към вашите включени модели, ще трябва изрично да ги посочите . Например:
User.includes(:posts).where('posts.name = ?', 'example')
Ще изведе грешка, но това ще работи:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Имайте предвид, че includes
работи с association names
докато references
се нуждае от the actual table name
.