activerecordの関連するモデルをまとめて取得するメソッドのincludesが多段の関連モデルでも使えた
例えば、以下のような3層にまたがる関連モデルがあるとすると、
class Team has_many :members end class Member belongs_to :team has_many :tasks end class Task belongs_to :member end
この場合、Taskのインスタンスオブジェクトから、
関連するTeamオブジェクトの情報を呼び出す場合、
task = Task.last task.member.team.name => "A team"
こうなって、SQL的には、
SELECT `tasks`.* FROM `tasks` LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 6 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 5 LIMIT 1
こうなります。
一見問題ないようにも見えますが、
仮にTaskオブジェクトを
Task.all
のように取得してeach等でループする場合、
Taskオブジェクトの数だけ、membersテーブルとteamsテーブルにアクセスしてしまいます。
tasks = Task.limit 10 tasks.each {|task| p task.member.team.name }
SELECT `tasks`.* FROM `tasks` LIMIT 10 SELECT `members`.* FROM `members` WHERE `members`.`id` = 6 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 5 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 4 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 4 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 4 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 4 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 6 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 5 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 6 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 5 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 6 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 5 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 4 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 4 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 3 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 3 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 2 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 2 LIMIT 1 SELECT `members`.* FROM `members` WHERE `members`.`id` = 4 LIMIT 1 SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 4 LIMIT 1
そこで登場するのが関連するモデルをまとめて取得するメソッドのincludesです。
includesメソッドを多段の関連モデルで呼び出す場合は、以下のように記述します。
tasks = Task.limit(10).includes(:member => :team) tasks.each {|task| p task.member.team.name }
SELECT `tasks`.* FROM `tasks` LIMIT 10 SELECT `members`.* FROM `members` WHERE `members`.`id` IN (6, 4, 3, 2) SELECT `teams`.* FROM `teams` WHERE `teams`.`id` IN (5, 4, 3, 2)