まずはネストという言葉に関する定義の問題ですが、
諸橋さんが書いているように
、PostsコントローラはComments
コントローラを集約(aggregates)しますが、
内包(compose)する訳ではありません。

たとえば、管理画面に対応するAdminコントローラから、
Commentの削除や修正を行う場合に、AdminコントローラからCommentsコントローラを集約する事を考えると、その必要性が分かりやすいと思います。

PostsコントローラにCommentsを制御するコードを書いてしまう(内包してしまう)と、
Adminコントローラで同じ事をする必要が出来た場合に、
同じようなコードを書く必要が出てきます。

Don't Repeat Yourself!

結果として、メンテナンス性の悪いコードが出来上がります。
この事が、Postsコントローラの中でCommentsリソースを制御する
コードを書く事の問題の本質だと思います。
もちろん、あらかじめCommentsを集約する存在が
Postsしか無いと分かっている場合には問題ありません。

という事で、
続いて検索やCRUD以外の操作はどうするのかという問題について。

この問題を考えるための重要な視点として、最近のRailsやMerbでは、
リソースを制御するためのリソースコントローラと、
それ以外の制御をするための汎用コントローラの役割が分けて考えられるようになってきているという事があります。

上述の話の中で登場するコントローラを当てはめてみると、
以下のようになります。

|caption=コントローラの分類
|
|リソースコントローラ,汎用コントローラ
|
|Posts,Admin
|Comments,Dashboard

リソースコントローラとは、特定のモデルに対してCRUD(create, read, update, delete)操作を行う事に特化したコントローラです。

そう考えると、検索やCRUD以外の操作は、
汎用コントローラが行うのが自然な気がします。
例えば、ブログの記事(Posts)やコメント(Comments)
の検索を行う場合であれば、
SearchコントローラがPostsコントローラやCommentsコントローラ
を集約すればOK.
疑似コード的に表現すると、以下のような感じになります。

pre>>
Search#posts with_scope(query){ Posts#index }
Search#comments with_scope(query){ Comments#index }
<<--

この構造は2年ぐらい前にRailsで使ってみたのですが、
Railsのコントローラの実装がネストに向いていないので、
パフォーマンス上の問題に苦しみました。
Railsのコントローラは、フィルタの実行、アクションの実行だけでなく、レスポンスの作成を担っているので、ネストさせた場合に、
いったん作成したレスポンスを破棄する必要があるなど、無駄が大きいのです(Railsではお馴染みのDoubleRenderErrorが発生するのもこのせいです)

しかし今であれば、Merbを使う事によってこの問題は解決します。
Merbのコントローラはレスポンスの作成をする必要が無く、非常にシンプルなので、ネストさせてもパフォーマンスの問題はほとんどありません。

ということで、Merbを使えばみんなHappyになるよという話でした。

前回の記事の追補

前回の記事では、Aggregatorの#showで、POST, PUT, DELETEを
Aggregatedに委譲するという話を書きましたが、
例えばPostsコントローラがCommentsとTrackbacksの
2つのリソースを集約している場合に、
どちらのリソースに対する操作なのかを判別する方法を用意する必要があるので、どうやって実現するか書いておきます。

pre>>
posts/1 -> Posts#show
posts/1/comments -> Posts#show -> Comments
posts/1/trackbacks -> Posts#show -> Trackbacks
<<--

こんな感じに、posts/1/:resource に対するPOST, PUT, DELETEを、
:resourceに対応するリソースコントローラに委譲する感じですね。

posted by genki genki on Wed 21 Jan 2009 at 09:02 with 0 comments