Misalkan Anda perlu mendapatkan nama pengguna dari lima posting pertama. Anda segera menulis kueri di bawah ini dan nikmati akhir pekan Anda.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Bagus. Tapi mari kita lihat kuerinya
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
untuk mengambil semua posts
dan 1 query
untuk mengambil users
untuk setiap posting menghasilkan total 6 queries
. Lihat solusi di bawah ini yang melakukan hal yang sama, hanya di 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)
Ada satu perbedaan kecil. Tambahkan includes(:posts)
untuk permintaan Anda, dan masalah terpecahkan. Cepat, bagus, dan mudah.
Tapi jangan hanya menambahkan includes
dalam kueri Anda tanpa memahaminya dengan benar. Menggunakan includes
dengan joins
dapat mengakibatkan penggabungan silang bergantung pada situasinya, dan Anda tidak memerlukannya dalam banyak kasus.
Jika Anda ingin menambahkan ketentuan ke model yang disertakan, Anda harus merujuknya secara eksplisit . Misalnya:
User.includes(:posts).where('posts.name = ?', 'example')
Akan menimbulkan kesalahan, tetapi ini akan berhasil:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Perhatikan bahwa includes
bekerja dengan association names
sementara references
membutuhkan the actual table name
.