続・「正しい入力」「あり得る入力」「あり得ない入力」の話

いきなりタイトルをひっくり返すようだけれど、こう考えるほうが分かりやすい気がしてきた。

  • HTTPリクエストには、通常の操作で起こりえる「あり得るリクエスト」と、そうでない「あり得ないリクエスト」がある
  • 入力パラメータ(PHPだと例えば $_GET["hoge"])には、仕様上「正しい入力値」と、そうでない「正しくない入力値」がある

Strong Parametersの役割 は、「あり得ないリクエスト」を「あり得るリクエスト」に変換したり、例外としたりすることだ。だからこそ、モデルではなくコントローラに置かれた。

This new approach is an extraction of the slice pattern and we're calling the plugin for it strong_parameters (already available as a gem as well). The basic idea is to move mass-assignment protection out of the model and into the controller where it belongs.

The whole point of the controller is to control the flow between user and application, including authentication, authorization, and as part of that access control.

Riding Rails: Strong parameters: Dealing with mass assignment in the controller instead of the model

CSRF対策用のトークンが含まれない場合も「あり得ないリクエスト」。前回の記事でいう「あり得ない入力」がリクエストに含まれる場合も、「あり得ないリクエスト」として処理したければすればよい。

そうした処理を経れば、アプリケーションが処理すべきは「あり得るリクエスト」のみとなる。もちろん、「正しい入力値」と「正しくない入力値」の判別は済んでいないので、各入力パラメータの「バリデーション」が必要になる。

ユーザ入力のバリデーションは以上に尽きると思う。


ちなみに、以前の記事で触れた「ミクロ派」の主張(例:HTML構築時にも変数の文字エンコーディングをチェックすべき)は、ユーザ入力とは関係のない話だ。その変数はユーザ入力由来のものとは限らない。単純に、ぼくがテンプレートエンジンを作るとしたら、バインドされる変数の文字エンコーディングをチェックするだろう、といった程度の話だ。ライブラリやフレームワークが頑張ることで、アプリケーション開発者の負担や不安はむしろ軽減されるのではないか。

「正しい入力」「あり得る入力」「あり得ない入力」の話

メールアドレスとかの具体例を挙げていますが、一般論としては入力仕様が定義され、正しく理解していれば、自ずと「正しい入力」は定義できます。「正しい入力」以外がエラーとすべき物としか

Twitter / yohgaki: メールアドレスとかの具体例を挙げていますが、一般論としては入 ...

私ならバリデーションエラー(あり得ない入力)と入力ミス(あり得る入力)の区別ができないプログラマは要りません。

Twitter / yohgaki: 私ならバリデーションエラー(あり得ない入力)と入力ミス(あり ...

「正しい入力」「あり得る入力」「あり得ない入力」の区別はおもしろいと思った。

一般に、フォームからの入力が正しくなかった場合、レスポンスは「入力時のフォームの再現+エラーメッセージ」とすることが多いだろう。このとき、ユーザの入力値はそのまま表示させたい。だが、たとえばセレクトボックスについて考えると、オプションに存在しない入力値がリクエストされた場合に、入力時のフォームを再現できなくなる。月(1〜12)を選択するはずのセレクトボックスの入力値が「13」だったら、どのようなレスポンスを返せばよいのか。その場合、「13」は「あり得ない入力」とみなし、不正なリクエストである旨のみを知らせるレスポンスを返す、という考え方もあってよいのではないだろうか。

この考え方を実現しようとすると、「正しい入力」「あり得る入力」「あり得ない入力」を明確に区別する仕様が必要になる。月を入力するインターフェースがセレクトボックスではなくテキストボックスだったら、「13」は「あり得る入力」としなければならない。単なる入力ミスなのに、入力時のフォームが再現されず、不正なリクエストである旨のみ知らされても、ユーザは困ってしまう。

なお、バリデーションと呼ばれるのは、「正しい入力」と「正しくない入力(あり得る入力+あり得ない入力)」を判別する処理のことだろう。ならば、「あり得る入力」だって、バリデーションエラーということになる。いや、「あり得ない入力」とそれ以外を判別するのがバリデーションだというのであれば、「正しい入力」と「正しくない入力」を判別する処理は何と呼べばよいのか。

Rails4セキュリティ レボリューションズ

Strong Parametersは仕組みとしてコントローラで入力パラメータのバリデーションを推奨。

params.require(:user).permit(:name, :email)
my_params_validate(params) 

または

paramsオブジェクトからバリデーションメソッドを呼ぶ様に拡張

params.require(:user).permit(:name, :email).validate(self)
  1. 「コントローラで入力パラメータのバリデーションを推奨」している大垣さんにとって、Strong Parameters がそれっぽいものに見えた
  2. これはよいものだと講演で取り上げた
  3. しかし、実際には単なるフィルタだった(大垣さんが定義するところのバリデーションではなかった)
  4. バリデーションメソッドを別途追加しなければ辻褄が合わなくなった

という流れ。

とはいえ、こうしたメソッドをRailsコアチームに提案して、首尾よく実装されたら、それはそれで素敵なことだと思う。

追記(2013-07-19)

おおもとのスライドの28ページに、「追加するだけ」との吹き出しを伴って、.validate(self) の記述が追加された。

「追加するだけ」といえばそうなのだろうが、そのようなメソッドを自前で追加しなければならないこと自体、「コントローラで入力パラメータのバリデーションを推奨」などされていない証拠ではないのか。

いずれにしても、Strong Parameters が、大垣さんの想定するバリデーション処理でないことはもはや明らかだ。バリデーション処理でない Strong Parameters がコントローラに組み込まれたからといって、どうして「仕組みとしてコントローラで入力パラメータのバリデーションを推奨」などといえるのか

現に、Integrate strong_parameters in Rails 4 by guilleiguaran ・ Pull Request #7251 ・ rails/rails ・ GitHub を見れば、モデルによるバリデーションに、DHHが不満を感じていないことが分かる。

プロフィール
Web開発者。現在の関心事はシステム品質の改善(特に性能効率性と保守性)。JAPAN MENSA会員。
カテゴリ別アーカイブ
記事検索