ActiveRecordの検索結果に対してコレクション操作を呼び出せるのは何故?
モデルBookから返された@booksで、eachとかsortとか呼べるのはなんでかなと。
@books = Book.find(1) @books = @books.sort { |x, y| x.price <=> y.price }
とか
@books = Book.select('publish, AVG(price) AS avg_price').group('publish') @books.each do |book| puts "publish=" + book.publish puts "avg="+book.avg_price end
とか。
調べてみると、@booksは ActiveRecord::Relation というクラス。
Relationの中で、
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
としている。delegate は ActiveSupportがRubyの元の委譲の仕組みを強化したものらしい。
オブジェクト指向で言われる「委譲」のこと。
ここでは、:each つまりeachメソッドを、 :to_a(このクラス内ではメソッド) に委譲するということ。
to_aはメソッドで、配列化するメソッド。
メソッドに委譲するということは、メソッドの返り値に委譲するということ?
Relation#eachはつまり、Relation#to_a#each になるってことですかね。
じゃあ、sortは? delegate の中に入ってません。
ここでまた、method_missing の出番。
def method_missing(method, *args, &block) if Array.method_defined?(method) to_a.send(method, *args, &block)
そのメソッドが、Arrayクラスで定義されているものだったら、to_aに委譲する。
それでsortが動けていた模様。
delegate を後で動かして確認してみよう。
(ActiveRecord 3.0.9 を確認)