[cgiapp] RunmodeDeclare and ValidateRM incompatibility?

Rhesa Rozendaal perl at rhesa.com
Wed Jun 17 16:12:09 EDT 2009


Richard Jones wrote:
> In the following example code, which uses CAP::RunmodeDeclare for 
> runmode handling:
> 
> #-----------------------------------------------------------------------
> runmode edit ($id) {
>    my $errs = shift;
> 
>    $id || return $self->error('no id passed to edit'); # warn 'id:'.$id;
> 
>    my $data = $self->model->get_some_data($id);
> 
>    [ .. ]
>    return $self->tt_process($errs);
> }
> 
> #-----------------------------------------------------------------------
> runmode update ($id) {
>    # if param 'id' passed, return error to edit():
>    my $error_rm = $id ? 'edit' : 'default';
> 
>    my $dfv = $self->check_rm( $error_rm, '_update_validate_profile' )
>    || return $self->dfv_error_page;
> 
>    [ .. ]
> }
> 
> A url of '/myapp/update/1' via CA::Dispatch calls the 'update' runmode, 
> which captures the param '1' into the var $id. All works as advertised.
> 
> But if validation in update() fails, the 'update' runmode is required to 
> return the dfv error page for 'edit', but it doesn't, instead a fatal 
> error results from the consequence of edit() capturing the value of dfv 
> errors in $id, which then kills the model method as it tries to execute 
> an sql statement using the dfv errors hashref instead of an id value.
> 
> The problem seems to be that, according to the docs, RunmodeDeclare will 
> capture variables passed as $self->baz(1, "me") as well as from the 
> query object. So 'edit ($id)' means $id will capture anything passed 
> into the rm. What seems odd is that the dfv errors hashref is also 
> captured in the first arg shifted from @_:

That's the issue: the arguments aren't shifted off @_, they're assigned from 
it. CAP::RD rewrites this:

   runmode something ($some, $variables)

into this:

   sub something {
     my $self = shift;
     my ($some, $variables) = @_;

     $some = $self->query->param('some') unless defined $some;
     $some = $self->param('some')        unless defined $some;
     ...

In other words, it tries treating the signature as a regular method signature 
first, and only falls back to looking in $self->query or $self->param if the 
variables are still undefined.

And it also explains why you got the errs hashref in both $id and $errs, since 
@_ is still unchanged.


> runmode edit ($id) {
>    my $errs = shift;
> 
>    warn Dumper $id; # contains the dfv errors hashref
>    warn Dumper $errs; # also contains the dfv errors hashref !!
> 
>    [ .. ]
> }
> 
> Of course it all works fine if I switch back to conventional runmode 
> handling, or to AutoRunmode.

The other solution would be to recognise that dfv_error_page passes the dfv 
hashref as the first argument, and name that in your signature:

   runmode edit ($errs, $id) { ...

That way, $errs is picked up from @_, while $id is picked up from either 
$self->query or $self->param (provided dfv_error_page doesn't pass additional 
parameters).

HTH,
Rhesa


More information about the cgiapp mailing list