Cascaded Eager LoadingがRails 1.1に間に合った!
http://dev.rubyonrails.org/changeset/3769
もうじき出ると云う噂のRails 1.1にCascaded Eager Loadingが間に合ってsvn headにコミットされた!これRails 1.0 => 1.1のActiveRecordの変更点の中じゃ一番大きいと云っても過言ではない機能。今までは二つ以上の関連のSQLを一回で引くにはSQL直書きしなくちゃならなかった*1のを一発で引けるという!
これで今までは二つ以上の関連を参照するには長いSQL書いてたり、長いSQLよくわからないのでパフォーマンス落ちるけどSQL複数回発行してたり(オレ)なんかにはめっちゃありがたい。鼻血物!!!
http://wota.jp/ac/?date=20060217#p01
な関連テーブルを一発で引きたい場合、
>> Group.find(:all, :include => [{:members => :favorites}]) => [#<Group:0x40be8fb8 @members=[#<Member:0x40be87e8 @attributes={"name"=>"secondlife", "group_id"=>"1", "id"=>"1"}, @favorites=[#<Favorite:0x40be80f4 @attributes={"name"=>"konkon", "member_id"=>"1", "id"=>"1"}>, #<Favorite:0x40be7758 @attributes={"name"=>"syokotan", "member_id"=>"1", "id"=>"2"}>]>, #<Member:0x40be6f74 @attributes={"name"=>"antipop", "group_id"=>"1", "id"=>"2"}, @favorites=[#<Favorite:0x40be6254 @attributes={"name"=>"ayaya", "member_id"=>"2", "id"=>"3"}>]>], @attributes={"name"=>"SubTech", "id"=>"1"}>]
で引ける!実際に発行しているSQLは
SELECT groups."id" AS t0_r0, groups."name" AS t0_r1, members." id" AS t1_r0, members."name" AS t1_r1, members."group_id" AS t1_r2, favorites."id" AS t2_r0, favorites."name" AS t2_r1, favorites." member_id" AS t2_r2 FROM groups LEFT OUTER JOIN members AS members ON members.group_id = groups.id LEFT OUTER JOIN favorites AS fav orites ON favorites.member_id = members.id
またもちろんconditionsでwhere句の指定も楽々。
>> Group.find(:all, :include => [{:members => :favorites}], :conditions => ['favorites.name = ?', 'konkon']) => [#<Group:0x40b8b930 @members=[#<Member:0x40b8b5c0 @attributes={"name"=>"secondlife", "group_id"=>"1", "id"=>"1"}, @favorites=[#<Favorite:0x40b8b318 @attributes={"name"=>"konkon", "member_id"=>"1", "id"=>"1"}>]>], @attributes={"name"=>"SubTech", "id"=>"1"}>]
実際に発行しているSQLは
SELECT groups."id" AS t0_r0, groups."name" AS t0_r1, members." id" AS t1_r0, members."name" AS t1_r1, members."group_id" AS t1_r2, favorites."id" AS t2_r0, favorites."name" AS t2_r1, favorites." member_id" AS t2_r2 FROM groups LEFT OUTER JOIN members AS members ON members.group_id = groups.id LEFT OUTER JOIN favorites AS fav orites ON favorites.member_id = members.id WHERE (favorites.name = 'konkon')
実装の詳しい内容はソース読むか Eager loading with cascaded associations の For Developers でふれられている。
というわけで舞波乙!
おまけ、すぐに試したい人用にさっきのサンプルデータのmigrateとmodelのソース。
db/migrate/001_init.rb
class Init < ActiveRecord::Migration def self.up create_table :groups do |t| t.column :name, :string end create_table :members do |t| t.column :name, :string t.column :group_id, :string end create_table :favorites do |t| t.column :name, :string t.column :member_id, :integer end g = Group.create :name => 'SubTech' m1 = Member.create :name => 'secondlife', :group_id => g.id m2 = Member.create :name => 'antipop', :group_id => g.id Favorite.create :name => 'konkon', :member_id => m1.id Favorite.create :name => 'syokotan', :member_id => m1.id Favorite.create :name => 'ayaya', :member_id => m2.id end def self.down end end
class Favorite < ActiveRecord::Base belongs_to :member end class Group < ActiveRecord::Base has_many :members end class Member < ActiveRecord::Base has_many :favorites belongs_to :group end
*1:http://wota.jp/ac/?date=20060217#p01 みたいに