ぼくが見ているレール(map.resouces編)

先日のQConで大場さんもおっしゃっていたことですが、Railsで開発をする上でものすごく重要なポイントに、Railsの敷いたレールから降りないというのがあります。別にコレはRailsが不自由だというわけでなく*1、通り一遍のものしかできないというわけでもなく、ただ基盤と相性の悪い設計すればあとで苦労するという、当然の話なわけです。
最近、私を含めいろいろな方が「レールから降りないで作るのが重要」と話しています。が。じゃあそのレールはどこにあるのかという話はあまり聞かれません。ということで、ふだん私がRailsアプリを設計するときに意識しているレールを言語化してみて、議論なりのたたき台にしたいな、と思った次第です。

とはいえDB周りは「羽生さんのERDレッスン嫁」で7割くらい済む話*2なので、まずはコントローラから。

設計指針としてのmap.resouces

Rails 2.xにおいて、コントローラの設計というのはつまりユーザに対して提供するリソースの設計に他なりません。このとき気をつけていることは「scaffoldに似せる」、言い換えると「リソースのCRUDを意識する」ということです。

もう少し極端に言うと、map.resoucesをちゃんと使ってるか、という感じです。Railsレシピブックにも書きましたが、map.resoucesはとてもいい感じにルーティングを定義してくれます。すなわち

  • 複数件取得 (index, GET /resouces)
  • 一件取得 (show, GET /resouces/:id)
  • 一件作成 (create, POST /resouces)
  • 一件取得 (update, PUT /resouces/:id)
  • 一件削除 (destroy, DELETE /resouces/:id)

の5つですね。この5つでうまくリソースをCRUDできるように作るのが基本だと思ってます。

ほかにも新規作成画面(new)と編集画面(edit)がありますが、アレはリソースのCRUDには直接関係ないアクションだと割り切るといいかと思います。ようは入力補助画面というか、狭義のUIというか。

コントローラの責務

で、コントローラの各アクションで実装すべき責務のうち最も重要なのは上述のmap.resoucesから導かれるそれぞれの役割を果たすことです。当然ですね。要するに適切なリソースをロードして、リソースのロジックをキックしてあげることです。さらにもう一つはユーザにレスポンスを返すこと。コレはredirectしたり適切なテンプレートをrenderしたりするってことです。

読み取り系(index, show)のアクションであれば、目的のリソースをちゃんと検索してロードすることが主な責務です。いまだとnamed_scopeなんかを使うとよいんじゃないでしょうか。
書き込み系(create, update, destroy)であれば、目的のリソースをロードしたりnewしたりした上で、saveとかdestroyとか業務的に必要な類似メソッドなどをキックすることが第一の責務です。さらにその結果をうけて「入力補助画面」を再表示したり、できたリソースへ遷移したりするといいと思います。

これの組み合わせでうまく要求仕様を満たすように、リソースを見いだすように心がけるといい感じです。もちろん見いだすのは難しいですけど。少なくとも方向性を意識しておくといいんじゃないでしょうか。
で、見いだしたあとの実装はscaffoldで生成されるのがだいぶいい感じなのでじろじろ読んでみてくださいな。

続くかも

例によって短くまとめられなかったですがこんな感じで。続きネタとしては

  • よく見るはまりどころ
    • 確認画面 => それJSで
    • ウィザード => それJSで
    • 複数項目を一気に入力 => それJSで
    • アップロード内容をプレビュー => 仕様を落とすorガンバレ!!
  • ビューとコントローラのインターフェース => paramsにアサインされる仕組み(レシピ本に書いたよ!!)
  • コントローラとモデルのインターフェースの作り方 => 基本はHashと文字列と配列。おおRubyだ。
    • 「モデル」と「リソース」は何が違うの? => だいたい同じように扱うけど機嫌とシステム内での意味が違うよ。ただ、単に帽子違いだったりもすることもそれなり
  • アクセス権 => scope_doの話をしたときにも書いた
    • ルーティングのネストとARのアソシエーション
  • テストの書き方 => 仙台で話した
    • Cucumberで外堀を埋める
    • step_definitionsとかカスタムmatcherは、プロジェクト内で"育てて"いくのがいいんじゃないか!!

のあたりをもう一度まとめておけるといいな、と思います。

*1:まぁそれなりに制限はありますが

*2:残りはARの機能の使い方になるかと