findもwhereも所詮クラスメソッド (特異メソッド)に過ぎない!(のか?)
RailsでModelにModuleをextendしたら、Moduleのメソッドは、Modelからクラスメソッドっぽく使える(特異メソッド?)
— kppaz (@kpinput) 2019年5月7日
そのメソッドがActiveRecord::Relationを返すなら、where等と、メソッドチェーンができる
となるとwhere等もActiveRecord::Relationを返す、特異メソッドでしかない、のか?
業務中こんな感じのコードを見かけた。
class TestModel < ApplicationRecord ... extend(TestModule) ... end module TestModule def test_method ... end end
TestModel.test_medhod
割とよくある形だと思うが、
ModuleをextendしたらModelからクラスメソッド っぽく使える
という感じ。
ここで1つ疑問。
これっていつもModelに使っているfindやらwhereやらも、
こんな感じでextendでmoduleとして組み込まれて、
クラスメソッド (特異メソッド)として使えるようになっているだけなんじゃないだろうか?
調査の結果、上の仮説はおおよそ正しいと言えそうだ。
以下のサイトが参考になった。
AR::Baseでは、まずAR::Queryingをextendし、
この中でAR::Relationのインスタンスに対してfindメソッド等をdelegateすることで使えるようにしている。 ※ AR=ActiveRecord
これを踏まえてActiveRecordを見てみると、 確かにextend 及び delegateされているのが分かる。
class Base extend ActiveModel::Naming extend ActiveSupport::Benchmarkable extend ActiveSupport::DescendantsTracker extend ConnectionHandling extend QueryCache::ClassMethods extend Querying
https://github.com/rails/rails/blob/430a09514a/activerecord/lib/active_record/querying.rb
module Querying delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, to: :all ... delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all
実はdelegateのことはよく分かっていないが、 大筋であっているんじゃないかなぁ。。。(適当)