RailsでのURL設計を考えてみる(3) 確認画面のURLは必要か

今度は「Rails3 失敗から学ぶDevise利用時のURL設計 - 130単位」のコメントをきっかけに考えてみました。

routes.rbの書き換え

新規登録のときに確認画面や完了画面がほしいという場合はよくあります。
もともと

match 'user_entry/profile'
match 'user_entry/setting'
post  'user_entry/confirm'
post  'user_entry/create'
get   'user_entry/complete'

だったものを、

resource :user, :only => :show do
  resource :profile, :except => [:show, :destroy]
  resource :setting, :except => [:show, :destroy]
end

とするのはどうか、と考えました*1
"user_entry"が"user"に変わっているのはまあ置いておいて、"confirm"と"complete"がなくなっています。
確認画面のために"confirm"というアクションを作るのはけっこう一般的なようで、「STEP 11: 確認画面(1) - Ruby on Rails ステップ・バイ・ステップ - Ruby on Rails with OIAX」でも紹介されていますが、あまりいいとは思えません。URLの"confirm"がリソースとして何を指すのかよくわからないからです。「GETできないURLがあったら何か変」です。
"confirmation"(確認書、確認するもの)ならGETできるリソースになり得ますが、主目的として確認画面を作ったり取得したりするわけではないので、わざわざ名前をつけるだけの価値はないでしょう。"complete"(completion)も同様です。
ということで、URLは用意せずに実装することになります。
(末尾の補足も参照)

実装の方針

単純には、確認済みかどうかのフラグをつけて処理することになるでしょう。下の記事の方法は、コントローラの書き換えなしにビューだけで実現していて参考になると思います。

また、完了画面は、POSTのレスポンスとして直接返せばいいでしょう。

APIを設計すると考える

「確認画面があるからそのURLを…」というふうに、画面からURLを設計するとうまくいかないのではないでしょうか。Ajaxが入ってくるとなおさらそうなる気がします。
1つの考えとしては、最初からAPIを作るんだと思ってURLを設計すると、基本操作がCRUDであることが意識されるのでいいのではないかと思います。Railsでは、それはroutes.rbでresources(resource)を使うことにつながります。

WebサービスとWeb APIを分けて考えない、これが、リソース設計で最も重要な考え方です。

「Webを支える技術」p.310

補足

追加アクション

"confirm"などの追加のアクションはオーバーロードPOST*2であるから、URLは動詞でよいしGETできなくてかまわない、という考えがあって、たぶんRailsもその考えに沿っている感じがするのですが、これにはあまり同意できません。URLとして現れるものは、基本的にGETできる(リソースとして意味がある)べきだと思います。

多くのWebアプリケーションは、オーバーロードPOSTを通じてサポートする操作のために、新しいURIを作成する。たとえば /weblog/myweblog/rebuild-index のようなURIは、そのURIにリンクしても意味はない。このようにURIにメソッド情報を含める代わりに、既存のリソース(/weblog/myweblog)でオーバーロードPOSTをサポートし、入力表現でメソッド情報(method=rebuild-index)を要求すればよい。

「RESTful Webサービス」p.229

結局、URLにアクションが含まれるというマッピングが間違いの元なので、自分の考えをもっとシンプルに実現するにはresourcesメソッドへのパッチでも書いたほうがよさそうです。
ちなみにresourcesでデフォルトで生成されるnew、editアクションはちゃんとGETできて、リソースとしての意味があるので問題ありません。

トランザクションリソース

元記事の仕様では"profile"→"setting"→"confirm"という画面遷移が想定されています。これは、profileとsettingをいったん仮入力させて、confirmですべてを確認させて一括で確定する、という意図だと思います。
こういう一括処理をおこなうために、トランザクションリソースという少し込み入った設計が必要になることがあります。これは今回はあえて無視しました…。
ただ、この仕様なら一括処理しなくてもさほど問題はないようにも思います。

*1:実際には「マイページ」部分も含めた10行をこの4行に置き換えている

*2:CRUDでうまく表現できない操作を、POSTで代用する方法