DBIx::Class::Validation

DBIx::Class::Validation - Validate all data before submitting to your database. - metacpan.org
モデル層でValidationするモジュールなんだけど、単純にCatalystで使ってみたらイマイチだったのでメモ。
イマイチというのはコントローラが思いのほか汚くなってしまうということと、確認画面があるようなフォームだとモデル層に行く前(insert/updateする前、確認用アクション)でValidationすることになるので単純に使えないということです。また、特にtxn_doとか使うとevalばっかになって嫌な感じです。

sub create_save : Path('create/save') {
    my ($self, $c) = @_; 

    if ($c->session->{entry}) {
        eval {
            $c->model('DBIC')->schema->txn_do(sub{
                eval {
                    $c->model('DBIC::Entry')->create({
                        %{$c->session->{entry}},
                        user_id => $c->user->obj->id,
                    }); 
                };  
                if ($@) {
                    $c->stash->{result} = $@; 
                    die "validation error";
                }   
            }); 
        };  
        if ($@) {
            $c->stash->{template} = 'entry/create.tt';
            return;
        }   

        $c->session_expire_key(entry => -1);
    }   

    $c->res->redirect($c->uri_for('/entry'));
}

もともと確認画面を表示してからここに来るフローだったので、セッションに格納したデータを使ってますがこの話には関係ありません。
また、スキーマクラスではこんな感じにvalidationを設定しています。
autoをセットした場合はinsert/updateの際に自動でvalidateを行い、エラーの場合はFormValidator::Simple::Resultsを例外として投げます(croakします)。

__PACKAGE__->validation(
    module => 'FormValidator::Simple',
    profile => [
        title => ['NOT_BLANK', ['JLENGTH', 0, 255]],
        body => ['NOT_BLANK', ['JLENGTH', 0, 2000]],
    ],  
    filters => 0,
    auto => 1,
);

txn_doの中と外でevalを使っていますが、txn_doの外だとvalidationのresultを$@経由で受け取れなかったためです(なぜか1になっていた)。

    • -

さて、よくよく追っていくとこのモジュールはHandelで使うために作られたようなモジュールみたいなのでこういうことになるのかなと思いました。HandelではHandel::Storage::DBICでValidationクラスとしてHandel::Components::Validation(DBIx::Class::Validationのサブクラス)を使うようになっています。そしてDBIx::Class::Schemaのexception_action()を使用してHandel独自の例外クラスを投げるという仕組みのようです。コントローラから実際のモデルクラスまでが遠く、その間のラップクラスがうまいことやっているおかげでコントローラからキレイに使えるようになっているのではないかなーと想像しています(実際にどうかは使ったことがないのでわかりませんが)。

    • -

http://takatoshi.dyndns.org/trac/tktsh/changeset/88