drapergem/draperのコードリーディングの備忘録。

lib/draper/railtie.rbにRailtieが定義されています。

メインは以下で、特にactive_recordに対するDraper.setup_ormメソッドが重要です。

  • app/decoratorsディレクトリ以下のファイルをeager_loadする
  • Draper.setup_action_controller
  • Draper.setup_action_mailer
  • Draper.setup_orm

setup_ormはDraper::DecoratableをActiveRecord::Baseにincludeします。

ActiveRecordに対してdecorateを呼び出すときはDraper::Decoratableのdecorateメソッドが呼び出されます。ここでは”モデル名” + “Decorator” の名前のクラスのdecorateメソッドを呼び出します。

Draper::Decoratorをextendしている場合、decorateメソッドはnewメソッドへのエイリアスなのでActiveRecordに対してdecorateを呼ぶと、Decoratorのインスタンスが生成されつつ元のオブジェクトが引数として渡されます。まさにDecoratorの作り方そのもので、元のオブジェクトはobjectプロパティとしてアクセスができます。

delegate_allを呼び出している場合はDraper::AutomaticDelegationがincludeされます。

AutomaticDelagationはmethod_missingに関するオーバーライドになります。objectがメソッドを持っていれば委譲し、そうでなければ本来のmethod_missingを呼び出します。

ActiveRecord::Relationの場合はクラスメソッドのdecorateが呼び出されます。

decorator_classのdecorate_collectionメソッドはモデル名の複数系(pluralize) + “Decorator” の名前のデコレータを検索し、decorate_collectionメソッドを呼び出します。対象のデコレータが存在しない場合は、Draper::CollectionDecoratorがdecorate_collectionメソッドを呼び出すことになります。

このオブジェクトはArray系のメソッドをdecorated_collectionに委譲します。

decorated_collectionはActiveRecord::Relation#mapによってデコレートしたActiveRecordの配列を生成します。この配列に対してArray系のメソッドを委譲することで、デコレートされたActiveRecordの配列を透過的に利用できます。

また、Draper::DecoratorやDraper::CollectionDecoratorはDraper::ViewHelpersをincludeしています。これによって各デコレータからhメソッドによってヘルパーメソッドを呼び出すことが可能になります。

Draper::ViewContextはActionControllerにincludeされます。これはActionControllerのview_contextを利用するためです。

ViewContextは基本的にview_contextメソッドをhookしてRequestStoreにview_contextを保存します。RequestStoreはThread.currentを使ってリクエストごとにグローバル変数を保存、取得できるクラス+ミドルウェアです。

Draper::HelperProxyはこんな感じで、method_missingをするとview_contextにdelegateするものの、define_methodでメソッドを動的に定義するため2回目移行はmethod_missingが叩かれず、オーバーヘッドを減らしています。

デコレータクラス内でdecorates_associationを呼び出すとアソシエーションのメソッドを動的に定義します。

Draper::DecoratedAssociation#callはDraper::Factory#decorateでアソシエーションをデコレートします。

Draper::Factory#decorateはさらにWorkerに処理を委譲します。

Worker#callでやっていることは、アソシエーションのデコレートです。collectionであればdecorate_collectionが呼ばれ、単一レコードであればdecorateメソッドが呼ばれます。