読者です 読者をやめる 読者になる 読者になる

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 みたいに