やーっぱり、ハマりました。CakePHPのSecurityコンポーネントです。
Bakeして吐き出したコードを使ってもブラックホール行きで、毎度ゴミ箱に投げ捨てられている気分です。
少し分かったのは、フォーム出力されたデータ項目と入力されたデータ項目(これPOSTでなくPUTなんです)が異なると、ブラックホール行きになる事です。
で、何が問題だったかというと、入力されたデータがフォーム出力された項目より少なくなっていた、事でした。Form->input で「parent_id」と名付けた項目が何故か option要素のないselect要素で出力されたため、data[Model][parent_id]という入力データが無かったのでした。
回避策としてビューで
$this->Form->unlockField('Model.parent_id');
を実行しておけばOKです。
2012-03-08 以下ダメポなので一旦取り消し、要再調査とします。
しかし、そう言う事で毎度煩わされることなく、もう少し能動的にチェックする方法がないか考えてみました。それが次の方法です。
フォームデータの有無でチェックに引っかかることなくCSRFを回避すると共に、Securityコンポーネントを利用する事でページバックによる再入力も避けられます。
「beforeFilter()」で「$this->Security->validatePost = false;」として、フォームデータをチェックをしないようします。ところが、これをするとCSRFのチェックもしなくなってしまうので、次のように入力のワンタイムトークンのデータと、セッションに保存されたデータが等しいかチェックするメソッドを用意します。
protected function _checkToken() { if (isset($this->params['_Token']['key'])) { if ($this->params['_Token']['key'] != $this->Session->read('_Token.key')) { return false; } } return true; }
アクションで _checkToken()メソッドを読み出せば確認できます。
AppControllerクラスで定義して、共通利用するようにすれば楽です。
(CakePHP 2.1 RC)