has_manyの :extend オプション
メモ。Rails2.3.8のドキュメントより。
has_many のブロック中にメソッド定義することで、関連で使えるメソッドを追加できる。
class Account < ActiveRecord::Base has_many :people do def find_or_create_by_name(name) first_name, last_name = name.split(" ", 2) find_or_create_by_first_name_and_last_name(first_name, last_name) end end end person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson") person.first_name # => "David" person.last_name # => "Heinemeier Hansson"
複数の関連中で共通に使うようなメソッドがある場合、モジュールにまとめて:extendオプションで指定することでDRYにできる。
module FindOrCreateByNameExtension def find_or_create_by_name(name) first_name, last_name = name.split(" ", 2) find_or_create_by_first_name_and_last_name(first_name, last_name) end end class Account < ActiveRecord::Base has_many :people, :extend => FindOrCreateByNameExtension end class Company < ActiveRecord::Base has_many :people, :extend => FindOrCreateByNameExtension end
配列に入れることで複数のモジュールを使える。同名のメソッドが存在した場合、配列の後にあるモジュールのメソッドの方が有効になる。
class Account < ActiveRecord::Base has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension] end
関連のブロック中や、extendオプションで指定されるモジュール中で、関連元のオブジェクトなどを取得するためのproxy系メソッドが3つある。
- proxy_owner
- 関連元のオブジェクト
- proxy_reflection
- 関連オブジェクト
- proxy_target
- 関連先のオブジェクト。キャッシュされてない限りはemptyらしい