それでは、コントローラ側の処理を見ていきましょう。
inputアクションでは、入力値チェックを行い、入力エラーが無い場合にTokenを作成します。そしてcompleteアクションで、そのTokenの検証を行って、正しい場合のみ値の保存を行います(今回は省略しています)。
# 省略
# (1)Catalyst::Controller::RequestTokenから派生
BEGIN { extends 'Catalyst::Controller::RequestToken' }
# 省略
sub input :Local {
my ( $self, $c ) = @_;
if ($c->req->method eq 'POST') {
# validate parameters
$c->form(
name => ['NOT_BLANK', ['JLENGTH', 2, 10]],
name_kana => ['NOT_BLANK', 'KATAKANA', ['JLENGTH', 2, 30]],
zip => ['NOT_BLANK', 'ZIP_JP'],
phone => ['NOT_BLANK', 'NUMBER_PHONE_JP'],
email => ['EMAIL_MOBILE_JP'],
);
if ($c->form->has_error) {
$c->fillform;
} else {
# (2)Tokenを作成
$c->stash->{token} = $self->create_token;
$c->stash->{template} = 'confirm.tt';
}
}
}
sub complete :Local {
my ( $self, $c ) = @_;
# (3)Tokenの検証
$self->validate_token;
if ($self->is_valid_token) {
# Tokenが正しい場合のみデータを登録
} else {
# Tokenが不正な値だった場合に表示
$c->stash->{template} = 'token_error.tt';
}
# (4)Tokenの削除
$self->remove_token;
}
# 省略
# newでの警告防止
__PACKAGE__->meta->make_immutable(inline_constructor => 0);
記述している処理の流れを見てみましょう。
(1)Catalyst::Controller::RequestTokenから派生
Catalyst::Controller::RequestTokenの機能を有効にするために、Catalyst::Controllerから継承していたクラスを、Catalyst::Controller::RequestTokenから継承するように変更します。
現在のCatalystではMooseベースとなっているため、このままではnewされる際に警告が発生するので、ファイル末尾にあるmake_immutableを呼び出している場所で、このメソッドの引数として「inline_constructor => 0」を渡しています。もしデフォルトのままで組み込みサーバーを起動すると次のような警告メッセージが表示されます。
Not inlining 'new' for FormSample2::Controller::Root since it is not inheriting the default Moose::Object::new If you are certain you don't need to inline your constructor, specify inline_constructor => 0 in your call to FormSample2::Controller::Root->meta->make_immutable
(2)Tokenを作成
create_tokenメソッドを呼び出し、Tokenを作成します。そして作成されたTokenをStashに登録しています。ここで登録したTokenは、completeアクションに引き渡すためにconfirm.ttテンプレートではhiddenパラメータとして設定しています。
(3)Tokenの検証
登録アクションであるcompleteでは、Tokenの検証を行うためにvalidate_tokenメソッドを呼び出しています。
Tokenは、リクエストパラメータとセッションの両方に登録されており、その両方の値が同じかどうかによって不正な呼び出しが実行されていないかを確認しています。
検証結果の確認は、is_valid_tokenメソッドで行います。ここではValidであることが確認できた場合にデータを保存しています。
(4)Tokenの削除
そしてTokenの検証が終わったら、セッションからTokenを削除します。
(2)で作成したTokenは、テンプレートで次のように登録しています。Tokenのパラメータ名は「_token」がデフォルト値として使用されます。
# 省略 <form method="post" action="complete"> <input type="hidden" name="_token" value="[% token %]" /> <input type="hidden" name="name" value="[% c.req.params.name %]" /> <input type="hidden" name="name_kana" value="[% c.req.params.name_kana %]" /> <input type="hidden" name="zip" value="[% c.req.params.zip %]" /> <input type="hidden" name="phone" value="[% c.req.params.phone %]" /> <input type="hidden" name="email" value="[% c.req.params.email %]" /> <input type="submit" name="submit" value="登録" /> </form> # 省略
実行例
このRequestTokenサンプルを実行してみましょう。次のURLをブラウザで表示させます。
http://<ホスト名またはIPアドレス><:Port>/input
FormValidatorでOKとなる値を入力し、確認画面を表示させると次のようになります。

[登録]ボタンを押下するとTokenをパラメータに設定して送信するため、次のように登録完了画面が表示されます。

意図的にTokenを送信しない場合の操作、ここでは[Token無しで登録]ボタンを押下した場合には、次のような画面が表示されます。

このように、RequestTokenを使用すると、1回だけ実行させたい処理などを行う際に簡単に導入できます。
