夏は海より山派の @RKTM です。 鈴鹿山脈の神崎川(愛知川)でじゃぶじゃぶ泳いでは滝壺に飛び込む夏休みでした。
Controllerの一覧を取得したい!
とある事情*1により、ApplicationControllerを継承したControllerの一覧を取得したいと思いました。 名前空間などを使って加工もしたいので、ファイル名ではなく、Classとして取得したいという要件。
ActiveSupportのsubclassesメソッド
調べてみると、ActiveSupport
でsubclasses
というメソッドが実装されているようです。
このメソッドは便利なのですが、直接の子どものクラスまでしか取得できず、 孫クラスやひ孫クラスまで取得できません。
再帰させて子孫までクラスを辿る
ということで再帰させてみました。
rails console Rails.application.eager_load! # 通常は名前が参照されるとautoloadされる。今回は強制的にロードする def list_descendants(*klasses) return klasses if klasses.empty? return klasses.map { |klass| list_descendants(*klass.subclasses) << klass }.flatten end list_descendants ApplicationController => [ApplicationController, ApiConnectorController, AbstractDocumentsController, DeliverySlipsController, EstimatesController, InvoicesController, AccountReceivableGuaranteeRequestsController, Accounts::AddonsController,....]
これでApplicationControllerの子どもや孫たちをClassとして取得できました。
再帰なんて面倒だ!もっとシンプルなActiveSupport::DescendantsTracker.descendants
上記のことを一撃で実現してくれるのが、
Module: ActiveSupport::DescendantsTracker — Documentation for rails (3.0.0) です。
同じように実行してみましょう。
rails console Rails.application.eager_load! ActiveSupport::DescendantsTracker.descendants(ApplicationController) # (結果は省略)
最後に
あるクラスを継承する子孫クラスを取得するために、再帰する方法と、一撃で実現する方法を紹介しました。
条件分岐する必要がなければ、再帰ではなく、ActiveSupport::DescendantsTracker.descendants
を使うと良いのではないでしょうか。
ActiveSupportは色々と便利な機能がありますね!