HTML::FormFuでDBカラムのユニークチェックをする

調べたのでちょっとメモ。
ユニーク制約付きのカラムのユニークチェックをして違反してたらエラーメッセージを出す。

このMLを参考にした。
http://grokbase.com/topic/2007/09/25/html-formfu-force-error-on-field/yoP3-UCIz8etTxOgftmcYMqZEGA

1. evalとConstraint::Callbackを使う

DBICでupdate/createするコードをevalして$@に'duplicate entry'という文字列が含まれていたら、ダミーとして定義しておいたConstraint::Callbackにエラーフラグを立てるというもの。

---
action: /category/create
indicator: submit
auto_fieldset: 1

elements:
  - type: Text
    name: name
    auto_label: %n
    container_tag: div
    constraints:
      - Required
      - type: Callback
        message: 'The Category name already taken'

  - type: Submit
    name: submit
    value: 作成する
sub create : Local FormConfig {
    my ($self, $c) = @_;

    my $form = $c->stash->{form};

    if ($form->submitted_and_valid) {
        eval {
            $c->model('DBIC::Category')->create({
                name => $c->req->param('name'),
            });
        };
        if ($@ =~ /duplicate entry/i) {
            $form->get_constraint(name => 'name', type => 'Callback')->force_errors(1);
            $form->process();
        }
        else {
            $c->res->redirect($c->uri_for('/category/'));
            return;
        }
    }

    $c->stash->{template} = 'category/create_form.tt2';
}

ちょっと無理やり感が強い。

2. HTML::FormFu::DBICを使う

たぶんまだCPANにないんだけど、
http://html-formfu.googlecode.com/svn/trunk/HTML-FormFu-DBIC/
ここにあるから勝手に持ってきてインストール。

elements:
  - type: Text
    name: name
    auto_label: %n
    container_tag: div
    constraints:
      - Required
      - type: DBIC::Unique
        model: DBIC::Category
        message: 'The Category name already taken'
sub create : Local FormConfig {
    my ($self, $c) = @_;

    my $form = $c->stash->{form};

    if ($form->submitted_and_valid) {
		$c->model('DBIC::Category')->create({
			name => $c->req->param('name'),
		});
		$c->res->redirect($c->uri_for('/category/'));
		return;
    }

    $c->stash->{template} = 'category/create_form.tt2';
}

スッキリ。
ただCPANにも上がってないので不安。
でもHTML::FormFu自体がまだbetaでAPIも安定してないって書いてあるからまあいいかという気もする。