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

としている。delegateActiveSupportRubyの元の委譲の仕組みを強化したものらしい。
オブジェクト指向で言われる「委譲」のこと。
ここでは、: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 を確認)