[Catalyst-commits] r12155 - in trunk/examples/CatalystAdvent/root/2009: . pen

zamolxes at dev.catalyst.perl.org zamolxes at dev.catalyst.perl.org
Thu Dec 3 06:15:59 GMT 2009


Author: zamolxes
Date: 2009-12-03 06:15:58 +0000 (Thu, 03 Dec 2009)
New Revision: 12155

Added:
   trunk/examples/CatalystAdvent/root/2009/3.pod
Removed:
   trunk/examples/CatalystAdvent/root/2009/pen/formhandler.pod
Log:
day 3


Copied: trunk/examples/CatalystAdvent/root/2009/3.pod (from rev 12154, trunk/examples/CatalystAdvent/root/2009/pen/formhandler.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2009/3.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2009/3.pod	2009-12-03 06:15:58 UTC (rev 12155)
@@ -0,0 +1,414 @@
+=head1 Creating a simple blog with Catalyst, HTML::FormHandler, and DBIx::Class
+
+=head2 Introduction
+
+L<HTML::FormHandler> is a module for handling forms and HTTP requests
+that includes not only validation rules but, in case of DBIC models, the
+logic to save the model in your database.
+
+I like HTML::FormHandler because of its simplicity, extendability,
+and Moose integration that it provides.
+
+I prefer it over FormFu partly for subjective reasons, but most
+importantly ...
+
+=over
+
+=item *
+
+In HTML::FormHandler, the validation logic is done with validators
+written in Perl, and you can use previously-defined Moose constraints.
+
+=item *
+
+The standard way to initialize a FormFu object is done with a Catalyst
+plugin. I prefer to initialize different forms in the same controller
+action.
+
+=item *
+
+HTML::FormHandler gives me the confidence that it's flexible enough
+for any challenge.
+
+=back
+
+This tutorial includes a fairly simple example that provides an
+interface for viewing and editing articles in a blog, using
+HTML::FormHandler for the editing functionality.
+
+=head2 Setting up the project
+
+To start a new project ...
+
+ # catalyst.pl Blog
+
+Let's generate the model:
+
+ perl script/blog_create.pl model DB DBIC::Schema Blog::Schema \
+ create=static components=TimeStamp \
+ 'dbi:Pg:dbname=blog' 'blog' 'blog' '{ AutoCommit => 1 }'
+
+Our articles will be tagged (to make the form processing more
+interesting), so add a model representing tags
+in C<lib/Blog/Schema/Result/Tag.pm>
+
+  package Blog::Schema::Result::Tag;
+
+  use strict;
+  use warnings;
+  use base qw/DBIx::Class/;
+
+  __PACKAGE__->load_components(qw/Core/);
+  __PACKAGE__->table('tags');
+
+  __PACKAGE__->add_columns(
+      tag_id => {
+          data_type => 'integer' ,
+          is_nullable   => 0 ,
+          is_auto_increment => 1
+      },
+      name => {
+          data_type   => 'varchar',
+          size        => 100,
+          is_nullable => 0,
+      },
+  );
+  __PACKAGE__->set_primary_key('tag_id');
+  1;
+  </pre>
+
+Let's also add an Article model
+in C<lib/Blog/Schema/Result/Article.pm>:
+
+  package Blog::Schema::Result::Article;
+
+  use strict;
+  use warnings;
+  use base qw/DBIx::Class/;
+
+  __PACKAGE__->load_components(qw/TimeStamp InflateColumn::DateTime Core/);
+  __PACKAGE__->table('articles');
+
+  __PACKAGE__->add_columns(
+      article_id => {
+          data_type => 'integer' ,
+          is_nullable   => 0 ,
+          is_auto_increment => 1
+      },
+      ts => {
+          data_type     => 'datetime' ,
+          is_nullable   => 1,
+          set_on_create => 1,   
+      },
+      title => {
+          data_type   => 'varchar',
+          size        => 250,
+          is_nullable => 0,
+      },
+      content => {
+          data_type   => 'text',
+          is_nullable => 1,
+      },
+      summary => {
+          data_type   => 'text',
+          is_nullable => 1,
+      },
+      rank => {
+          data_type => 'decimal',
+          size        => [3, 2],
+          is_nullable => 1, 
+      },
+
+  );
+  __PACKAGE__->set_primary_key('article_id');
+  __PACKAGE__->has_many(article_tags => 'Blog::Schema::Result::ArticleTag', 'article_fk');
+  __PACKAGE__->many_to_many(tags => 'article_tags', 'tag');
+
+
+... with a corresponding link table ...
+
+  package Blog::Schema::Result::ArticleTag;
+
+  use strict;
+  use warnings;
+  use base qw/DBIx::Class/;
+
+  __PACKAGE__->load_components(qw/Core/);
+  __PACKAGE__->table('article_tag');
+
+  __PACKAGE__->add_columns(
+      article_fk => {
+          data_type   => 'integer',
+          is_nullable => 0,
+      },
+      tag_fk => {
+          data_type   => 'integer',
+          is_nullable => 0,
+      },
+  );
+  __PACKAGE__->add_unique_constraint([ qw/article_fk tag_fk/ ]);
+  __PACKAGE__->belongs_to(tag => 'Blog::Schema::Result::Tag', 'tag_fk');
+  __PACKAGE__->belongs_to(article => 'Blog::Schema::Result::Article', 'article_fk');
+
+We're almost done setting up our project. Now just deploy your
+schema with a command like this ...
+
+    # perl -I./lib -MBlog::Model::DB \
+         -e " Blog::Model::DB->new->schema->deploy "
+
+Also add these utilities to lib/Blog.pm ...
+
+  sub redirect_to_action {
+      my ($c, $controller, $action, @params) =@_;
+      $c->response->redirect($c->uri_for($c->controller($controller)->action_for($action), @params));
+      $c->detach;
+  }
+  sub forward_to_action {
+      my ($c, $controller, $action, @params) = @_;
+      $c->forward($controller, $action, @params);
+      $c->detach;
+  }
+
+=head2 Creating the CRUD controller
+
+Edit a new file in C<lib/Blog/Controller/Article.pm>:
+
+  package Blog::Controller::Article;
+
+  use strict;
+  use warnings;
+  use parent 'Catalyst::Controller';
+
+  # this class is a HTML::FormHandler class that we'll define below
+  use Blog::Form::Article;
+
+  sub articles : Chained('/') PathPart('article') CaptureArgs(0) {
+      my ($self, $c) = @_;
+      $c->stash->{articles} = $c->model('DB::Article');
+  }
+
+  sub list : Chained('articles') Args(0) {}
+
+  sub item : Chained('articles') PathPart('') CaptureArgs(1) {
+      my ($self, $c, $id) = @_;
+
+      $c->error("ID isn't valid!") unless $id =~ /^\d+$/;
+      $c->stash->{item} = $c->stash->{articles}->find($id);
+      unless ($c->stash->{item}) {
+          # $c->flash->{error_msg} = "Request article is not available!";
+          $c->response->status(404);
+          $c->forward_to_action('Article', 'list');
+      }
+  }
+
+  sub edit : Chained('item') {
+      my ($self, $c) = @_;
+      $c->forward_to_action('Article', 'add');
+  }
+
+  sub add : Chained('articles') {
+      my ($self, $c) = @_;
+      $c->forward_to_action('Article', 'add');
+  }
+
+  # both adding and editing happens here
+  # no need to duplicate functionality
+  sub save : Private {
+      my ($self, $c) = @_;
+
+      # if the item doesn't exist, we'll just create a new result
+      my $item = $c->stash->{item} || $c->model('DB::Article')->new_result({});
+      my $form = Blog::Form::Article->new( item => $item );
+
+      $c->stash( form => $form, template => 'article/save.tt' );
+
+      # the "process" call has all the saving logic,
+      #   if it returns False, then a validation error happened
+      return unless $form->process( params => $c->req->params  );
+
+      # $c->flash->{info_msg} = "Article saved!";
+      $c->redirect_to_action('Article', 'edit', [$item->article_id]);
+  }
+
+This CRUD is pretty standard, and it would be possible to abstract
+it away in a role (see  L<Catalyst::Manual::CatalystAndMoose/Controller_Roles>)
+
+=head2 The Editing Form
+
+Let's start with the HTML::FormHandler-derived class
+in C<lib/Blog/Form/Article.pm> looking like this ...
+
+  package Blog::Form::Article;
+
+  use strict;
+  use warnings;
+  use HTML::FormHandler::Moose;
+
+  extends 'HTML::FormHandler::Model::DBIC';
+  with 'HTML::FormHandler::Render::Simple';
+
+  has_field 'title'    => ( type => 'Text',     required => 1 );
+  has_field 'ts'       => ( type => 'Date', label => 'Published Date' );
+  has_field 'content'  => ( type => 'TextArea', required => 0 );
+
+  has_field 'tags_str' => ( type => 'TextArea', required => 0 );
+  has_field 'rank'     => ( type => 'Text',     default => '0.00' );
+
+  1;
+
+... and to make this work, also add the view ...
+
+  # perl script/blog_create.pl view TT TT
+
+... configure the templates path, and add the following file in
+C<root/article/save.tt> ...
+
+  <h1>
+    [% IF item.article_id %]Editing "[% item.title %]"
+    [% ELSE %]Adding a new article[% END %]
+  </h1>
+
+  [% IF info_msg %]<div class="info_msg">[% info_msg %]</div>[% END %]
+
+  [% form.render %]
+
+OK, so we now have a form with automatic validation.
+
+=over
+
+=item *
+
+The "title" field is required
+
+=item *
+
+The "published date" field expects the format YYYY-MM-DD. You'd be
+wise to enhance this input with a Javascript widget.
+
+=back
+
+The first problem ... the "tags_str" field is a
+textarea. HTML::FormHandler can work directly with many-to-many
+relationships, but in this case we want the editing to be as
+"free-form" as possible. So we want to specify those tags in a simple
+textarea, separated by commas.
+
+To save the tags, we want Blog::Form::Article to automatically get the
+value, split it in words by ",", create the missing tags, and create
+the necessary links between the article and those tags. We'll just
+append the following to Blog::Form::Article:
+
+  before 'update_model' => sub {
+      my $self = shift;
+      my $item = $self->item;
+
+      my @tags = split /\s*,\s*/, $self->field('tags_str')->value;
+      $item->article_tags->delete;
+
+      my $tags_rs = $item->result_source->schema->resultset('Tag');
+      foreach my $tag (@tags) {
+          my $tag_obj = $tags_rs->search({ name => $tag })->first
+            || $tags_rs->create({ name => $tag });
+          $item->article_tags->create({ tag => $tag_obj });
+      }
+  };
+
+We have this flexibility, since HTML::FormHandler is based on
+Moose. But we also want it to load the current tags in the textarea
+when the form renders. So we'll just append this:
+
+  after 'setup_form' => sub {
+      my $self = shift;
+      my $item = $self->item;
+
+      my $value = join ', ', map { $_->name }
+         $item->tags->search({}, { order_by => 'name' })->all;
+      $self->field('tags_str')->value($value);
+  };
+
+=head3 A custom type
+
+Another problem is with the "rank". We want this to be a decimal
+number between 0 and 5. An easy way to do this is with the field
+'range_start' and 'range_end' settings, but we'll demonstrate this 
+with a custom type and additional transformations:
+
+  package Blog::Form::Field::Rank;
+
+  use HTML::FormHandler::Moose;
+  extends 'HTML::FormHandler::Field::Text';
+
+  apply( [
+       { # remove a dollar sign
+         transform => sub {
+           my $value = shift;
+           $value =~ s/^\$//;
+           return $value;
+       }},
+       {
+         transform => sub { $_[0] =~ /^[\d+.]+$/ ? sprintf '%.2f', $_[0] : $_[0] },
+         message   => 'Value cannot be converted to a decimal',
+       },
+       {
+         check => sub { $_[0] =~ /^-?\d+\.?\d*$/ && $_[0] >= 0 && $_[0] <= 5 },
+         message => 'Rank must be a decimal number between 0 and 5'
+       }
+      ]);
+  1;
+
+And then the field declaration in the form class becomes ...
+
+  has_field 'rank' => ( type => '+Blog::Form::Field::Rank', default => '0.00' );
+
+=head3 Auto-generating values
+
+In our example, the Article model has a "summary" field. We want this
+to be autogenerated. I'm sure you can find on CPAN modules for
+doing this, and one stupid way of doing it would be to just delete the
+HTML tags and slice it to 200 chars or something.
+
+So to autogenerate the summary tag, add the following to
+C<Blog::Form::Article> ...
+
+  after 'update_model' => sub {
+      my $self = shift;
+      my $item = $self->item;
+  
+      my $summary = generate_symmary($item->content);
+      $item->update({ summary => $summary })
+        if $summary;
+  };
+
+=head2 Testing
+
+And we are done. Start your development server with:
+
+    perl script/blog_server.pl -r -d
+
+and go to the following URL ...
+
+    http://localhost:3000/article/add
+
+=head2 Download the project
+
+You can download this sample project with ...
+
+  svn co L<http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Advent09FormHandlerBlog>
+
+=head2 Further Reading
+
+See L<HTML::FormHandler::Manual::Intro> for a more complex example
+with custom validators and notes about template rendering.
+
+Also, check out L<HTML::FormHandler::Manual::Cookbook>,
+L<HTML::FormHandler::Manual::Tutorial> and the other documents in
+L<HTML::FormHandler::Manual>.
+
+=head1 AUTHOR
+
+Alexandru Nedelcu <alex at sinapticode.com>
+
+=head3 COPYRIGHT
+
+Copyright 2009 Sinapticode - L<http://www.sinapticode.com>
+

Deleted: trunk/examples/CatalystAdvent/root/2009/pen/formhandler.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2009/pen/formhandler.pod	2009-12-03 06:15:28 UTC (rev 12154)
+++ trunk/examples/CatalystAdvent/root/2009/pen/formhandler.pod	2009-12-03 06:15:58 UTC (rev 12155)
@@ -1,414 +0,0 @@
-=head1 Creating a simple blog with Catalyst, HTML::FormHandler, and DBIx::Class
-
-=head2 Introduction
-
-L<HTML::FormHandler> is a module for handling forms and HTTP requests
-that includes not only validation rules but, in case of DBIC models, the
-logic to save the model in your database.
-
-I like HTML::FormHandler because of its simplicity, extendability,
-and Moose integration that it provides.
-
-I prefer it over FormFu partly for subjective reasons, but most
-importantly ...
-
-=over
-
-=item *
-
-In HTML::FormHandler, the validation logic is done with validators
-written in Perl, and you can use previously-defined Moose constraints.
-
-=item *
-
-The standard way to initialize a FormFu object is done with a Catalyst
-plugin. I prefer to initialize different forms in the same controller
-action.
-
-=item *
-
-HTML::FormHandler gives me the confidence that it's flexible enough
-for any challenge.
-
-=back
-
-This tutorial includes a fairly simple example that provides an
-interface for viewing and editing articles in a blog, using
-HTML::FormHandler for the editing functionality.
-
-=head2 Setting up the project
-
-To start a new project ...
-
- # catalyst.pl Blog
-
-Let's generate the model:
-
- perl script/blog_create.pl model DB DBIC::Schema Blog::Schema \
- create=static components=TimeStamp \
- 'dbi:Pg:dbname=blog' 'blog' 'blog' '{ AutoCommit => 1 }'
-
-Our articles will be tagged (to make the form processing more
-interesting), so add a model representing tags
-in C<lib/Blog/Schema/Result/Tag.pm>
-
-  package Blog::Schema::Result::Tag;
-
-  use strict;
-  use warnings;
-  use base qw/DBIx::Class/;
-
-  __PACKAGE__->load_components(qw/Core/);
-  __PACKAGE__->table('tags');
-
-  __PACKAGE__->add_columns(
-      tag_id => {
-          data_type => 'integer' ,
-          is_nullable   => 0 ,
-          is_auto_increment => 1
-      },
-      name => {
-          data_type   => 'varchar',
-          size        => 100,
-          is_nullable => 0,
-      },
-  );
-  __PACKAGE__->set_primary_key('tag_id');
-  1;
-  </pre>
-
-Let's also add an Article model
-in C<lib/Blog/Schema/Result/Article.pm>:
-
-  package Blog::Schema::Result::Article;
-
-  use strict;
-  use warnings;
-  use base qw/DBIx::Class/;
-
-  __PACKAGE__->load_components(qw/TimeStamp InflateColumn::DateTime Core/);
-  __PACKAGE__->table('articles');
-
-  __PACKAGE__->add_columns(
-      article_id => {
-          data_type => 'integer' ,
-          is_nullable   => 0 ,
-          is_auto_increment => 1
-      },
-      ts => {
-          data_type     => 'datetime' ,
-          is_nullable   => 1,
-          set_on_create => 1,   
-      },
-      title => {
-          data_type   => 'varchar',
-          size        => 250,
-          is_nullable => 0,
-      },
-      content => {
-          data_type   => 'text',
-          is_nullable => 1,
-      },
-      summary => {
-          data_type   => 'text',
-          is_nullable => 1,
-      },
-      rank => {
-          data_type => 'decimal',
-          size        => [3, 2],
-          is_nullable => 1, 
-      },
-
-  );
-  __PACKAGE__->set_primary_key('article_id');
-  __PACKAGE__->has_many(article_tags => 'Blog::Schema::Result::ArticleTag', 'article_fk');
-  __PACKAGE__->many_to_many(tags => 'article_tags', 'tag');
-
-
-... with a corresponding link table ...
-
-  package Blog::Schema::Result::ArticleTag;
-
-  use strict;
-  use warnings;
-  use base qw/DBIx::Class/;
-
-  __PACKAGE__->load_components(qw/Core/);
-  __PACKAGE__->table('article_tag');
-
-  __PACKAGE__->add_columns(
-      article_fk => {
-          data_type   => 'integer',
-          is_nullable => 0,
-      },
-      tag_fk => {
-          data_type   => 'integer',
-          is_nullable => 0,
-      },
-  );
-  __PACKAGE__->add_unique_constraint([ qw/article_fk tag_fk/ ]);
-  __PACKAGE__->belongs_to(tag => 'Blog::Schema::Result::Tag', 'tag_fk');
-  __PACKAGE__->belongs_to(article => 'Blog::Schema::Result::Article', 'article_fk');
-
-We're almost done setting up our project. Now just deploy your
-schema with a command like this ...
-
-    # perl -I./lib -MBlog::Model::DB \
-         -e " Blog::Model::DB->new->schema->deploy "
-
-Also add these utilities to lib/Blog.pm ...
-
-  sub redirect_to_action {
-      my ($c, $controller, $action, @params) =@_;
-      $c->response->redirect($c->uri_for($c->controller($controller)->action_for($action), @params));
-      $c->detach;
-  }
-  sub forward_to_action {
-      my ($c, $controller, $action, @params) = @_;
-      $c->forward($controller, $action, @params);
-      $c->detach;
-  }
-
-=head2 Creating the CRUD controller
-
-Edit a new file in C<lib/Blog/Controller/Article.pm>:
-
-  package Blog::Controller::Article;
-
-  use strict;
-  use warnings;
-  use parent 'Catalyst::Controller';
-
-  # this class is a HTML::FormHandler class that we'll define below
-  use Blog::Form::Article;
-
-  sub articles : Chained('/') PathPart('article') CaptureArgs(0) {
-      my ($self, $c) = @_;
-      $c->stash->{articles} = $c->model('DB::Article');
-  }
-
-  sub list : Chained('articles') Args(0) {}
-
-  sub item : Chained('articles') PathPart('') CaptureArgs(1) {
-      my ($self, $c, $id) = @_;
-
-      $c->error("ID isn't valid!") unless $id =~ /^\d+$/;
-      $c->stash->{item} = $c->stash->{articles}->find($id);
-      unless ($c->stash->{item}) {
-          # $c->flash->{error_msg} = "Request article is not available!";
-          $c->response->status(404);
-          $c->forward_to_action('Article', 'list');
-      }
-  }
-
-  sub edit : Chained('item') {
-      my ($self, $c) = @_;
-      $c->forward_to_action('Article', 'add');
-  }
-
-  sub add : Chained('articles') {
-      my ($self, $c) = @_;
-      $c->forward_to_action('Article', 'add');
-  }
-
-  # both adding and editing happens here
-  # no need to duplicate functionality
-  sub save : Private {
-      my ($self, $c) = @_;
-
-      # if the item doesn't exist, we'll just create a new result
-      my $item = $c->stash->{item} || $c->model('DB::Article')->new_result({});
-      my $form = Blog::Form::Article->new( item => $item );
-
-      $c->stash( form => $form, template => 'article/save.tt' );
-
-      # the "process" call has all the saving logic,
-      #   if it returns False, then a validation error happened
-      return unless $form->process( params => $c->req->params  );
-
-      # $c->flash->{info_msg} = "Article saved!";
-      $c->redirect_to_action('Article', 'edit', [$item->article_id]);
-  }
-
-This CRUD is pretty standard, and it would be possible to abstract
-it away in a role (see  L<Catalyst::Manual::CatalystAndMoose/Controller_Roles>)
-
-=head2 The Editing Form
-
-Let's start with the HTML::FormHandler-derived class
-in C<lib/Blog/Form/Article.pm> looking like this ...
-
-  package Blog::Form::Article;
-
-  use strict;
-  use warnings;
-  use HTML::FormHandler::Moose;
-
-  extends 'HTML::FormHandler::Model::DBIC';
-  with 'HTML::FormHandler::Render::Simple';
-
-  has_field 'title'    => ( type => 'Text',     required => 1 );
-  has_field 'ts'       => ( type => 'Date', label => 'Published Date' );
-  has_field 'content'  => ( type => 'TextArea', required => 0 );
-
-  has_field 'tags_str' => ( type => 'TextArea', required => 0 );
-  has_field 'rank'     => ( type => 'Text',     default => '0.00' );
-
-  1;
-
-... and to make this work, also add the view ...
-
-  # perl script/blog_create.pl view TT TT
-
-... configure the templates path, and add the following file in
-C<root/article/save.tt> ...
-
-  <h1>
-    [% IF item.article_id %]Editing "[% item.title %]"
-    [% ELSE %]Adding a new article[% END %]
-  </h1>
-
-  [% IF info_msg %]<div class="info_msg">[% info_msg %]</div>[% END %]
-
-  [% form.render %]
-
-OK, so we now have a form with automatic validation.
-
-=over
-
-=item *
-
-The "title" field is required
-
-=item *
-
-The "published date" field expects the format YYYY-MM-DD. You'd be
-wise to enhance this input with a Javascript widget.
-
-=back
-
-The first problem ... the "tags_str" field is a
-textarea. HTML::FormHandler can work directly with many-to-many
-relationships, but in this case we want the editing to be as
-"free-form" as possible. So we want to specify those tags in a simple
-textarea, separated by commas.
-
-To save the tags, we want Blog::Form::Article to automatically get the
-value, split it in words by ",", create the missing tags, and create
-the necessary links between the article and those tags. We'll just
-append the following to Blog::Form::Article:
-
-  before 'update_model' => sub {
-      my $self = shift;
-      my $item = $self->item;
-
-      my @tags = split /\s*,\s*/, $self->field('tags_str')->value;
-      $item->article_tags->delete;
-
-      my $tags_rs = $item->result_source->schema->resultset('Tag');
-      foreach my $tag (@tags) {
-          my $tag_obj = $tags_rs->search({ name => $tag })->first
-            || $tags_rs->create({ name => $tag });
-          $item->article_tags->create({ tag => $tag_obj });
-      }
-  };
-
-We have this flexibility, since HTML::FormHandler is based on
-Moose. But we also want it to load the current tags in the textarea
-when the form renders. So we'll just append this:
-
-  after 'setup_form' => sub {
-      my $self = shift;
-      my $item = $self->item;
-
-      my $value = join ', ', map { $_->name }
-         $item->tags->search({}, { order_by => 'name' })->all;
-      $self->field('tags_str')->value($value);
-  };
-
-=head3 A custom type
-
-Another problem is with the "rank". We want this to be a decimal
-number between 0 and 5. An easy way to do this is with the field
-'range_start' and 'range_end' settings, but we'll demonstrate this 
-with a custom type and additional transformations:
-
-  package Blog::Form::Field::Rank;
-
-  use HTML::FormHandler::Moose;
-  extends 'HTML::FormHandler::Field::Text';
-
-  apply( [
-       { # remove a dollar sign
-         transform => sub {
-           my $value = shift;
-           $value =~ s/^\$//;
-           return $value;
-       }},
-       {
-         transform => sub { $_[0] =~ /^[\d+.]+$/ ? sprintf '%.2f', $_[0] : $_[0] },
-         message   => 'Value cannot be converted to a decimal',
-       },
-       {
-         check => sub { $_[0] =~ /^-?\d+\.?\d*$/ && $_[0] >= 0 && $_[0] <= 5 },
-         message => 'Rank must be a decimal number between 0 and 5'
-       }
-      ]);
-  1;
-
-And then the field declaration in the form class becomes ...
-
-  has_field 'rank' => ( type => '+Blog::Form::Field::Rank', default => '0.00' );
-
-=head3 Auto-generating values
-
-In our example, the Article model has a "summary" field. We want this
-to be autogenerated. I'm sure you can find on CPAN modules for
-doing this, and one stupid way of doing it would be to just delete the
-HTML tags and slice it to 200 chars or something.
-
-So to autogenerate the summary tag, add the following to
-C<Blog::Form::Article> ...
-
-  after 'update_model' => sub {
-      my $self = shift;
-      my $item = $self->item;
-  
-      my $summary = generate_symmary($item->content);
-      $item->update({ summary => $summary })
-        if $summary;
-  };
-
-=head2 Testing
-
-And we are done. Start your development server with:
-
-    perl script/blog_server.pl -r -d
-
-and go to the following URL ...
-
-    http://localhost:3000/article/add
-
-=head2 Download the project
-
-You can download this sample project with ...
-
-  svn co L<http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Advent09FormHandlerBlog>
-
-=head2 Further Reading
-
-See L<HTML::FormHandler::Manual::Intro> for a more complex example
-with custom validators and notes about template rendering.
-
-Also, check out L<HTML::FormHandler::Manual::Cookbook>,
-L<HTML::FormHandler::Manual::Tutorial> and the other documents in
-L<HTML::FormHandler::Manual>.
-
-=head1 AUTHOR
-
-Alexandru Nedelcu <alex at sinapticode.com>
-
-=head3 COPYRIGHT
-
-Copyright 2009 Sinapticode - L<http://www.sinapticode.com>
-




More information about the Catalyst-commits mailing list