[Catalyst] C::C::FormBuilder - Forwarding to another action overwrites data from the calling action

Danny Warren danny at io.com
Wed Feb 14 11:50:54 GMT 2007


Apologies, I should have mentioned that I was using the controller code =

from my first mail.  I have attached my test controller as Test.pm.

Thank you for your explanation about how $c->formbuilder works with =

forwards, that makes some of what I am seeing make more sense (and that =

I had some incorrect assumptions about how forwards worked, will brush =

up on the catalyst docs).

I should clarify my question from the previous mail, reading it again it =

wasn't very clear.

Based on the code you provided, I created a new Action::TT that attempts =

to place a copy of the fb objects in a hash so it can be later accessed =

by form name in the template (ex: forms.foo.FormBuilder).  My base =

controller is attached as Multiple.pm and my modified Action::TT is =

attached as TT.pm.

The problem is that, even though the C::C::FormBuilder code is called =

twice (once for each action), only the last form to be processed is kept =

in $controller->_formbuilder.  Makes sense, given what you explained =

below about forwards, but that still leaves me wondering how to:

a) grab the name of the form so I can put multiple forms in a stash hash =

(since _formbuilder->name is always that of the last form forwarded to)

b) put the correct form data in the stash for each form, since the data =

for the last form processed will always be in _formbuilder.

To see this in action, here is the log snippet from my last e-mail (you =

can see that C::C::FB runs against both actions, foo and foo_search, but =

that foo_search's data is the only thing that ends up in _formbuilder =

for both).  See attached TT.pm for how I am grabbing the form data, =

maybe I am doing it wrong...

   [debug] Form (foo): Looking for config file foo.fb
   [debug] Form (foo): Found form config =

/home/dwarren/MyApp/root/forms/foo.fb

   [debug] Form (foo_search): Looking for config file foo_search.fb
   [debug] Form (foo_search): Found form config =

/home/dwarren/MyApp/foo_search.fb

   [debug] ACTION: foo
   [debug] REAL ACTION: foo_search
   [debug] FORM NAME: foo_search

   [debug] ACTION: foo
   [debug] REAL ACTION: foo
   [debug] FORM NAME: foo_search


I also ran the same code you provided in your last e-mail, and it =

happens there as well - the data is for the last form that was forwarded =

to.  I would expect that C::C::FormBuilder is called as it comes across =

the action (which it is) but it looks like "setup_template_vars" happens =

later, once $_formbuilder has been populated with the forwarded data.

If I am just not grasping something, let me know.  Maybe there is =

something funky with my Catalyst environment as well (if your sample =

code works for you and it does not for me)?

Sorry again if this confusing or long-winded.  I have just been pulling =

my hair out on this one, and I don't think I know the guts of catalyst =

well enough yet to properly debug and explain what I am seeing.

Thank you again for your time!
Danny


Juan Camacho wrote:
> On 2/12/07, Danny Warren <danny at io.com> wrote:
>> It looks to me that forwarding from one "Form" action to another "Form"
>> action causes the FormBuilder data from the first action to be
>> overwritten.
>>
> =

>> Can you confirm this, or am I doing something wrong here?  I am still
>> somewhat green with Catalyst, so I might be misunderstanding exactly how
>> forwards work.  From reading the docs, I was under the impression that
>> two actions should not clobber each other upon forwarding (since
>> forwarded actions are processed inside an eval).
>>
> =

> Each action will have it's own formbuilder object instance. After you
> return from the forward to another form action, $self->formbuilder
> will be a brand new FormBuilder object.
> =

> sub foo : Form('foo') {
>   my ($self, $c) =3D @_;
>   # $self->formbuilder is for foo form
>   $self->forward('bar');
>   # now $self->formbuilder is for bar form
> }
> =

> sub bar : Form('bar') { ... }
> =

> Consequently, each action should do it's own thing with it's
> FormBuilder object -- e.g. validate, add or change form fields). Not
> sure what kind of problem you are having as a result of this since you
> didn't provide sample Controller code.
> =

> _______________________________________________
> List: Catalyst at lists.rawmode.org
> Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.or=
g/
> Dev site: http://dev.catalyst.perl.org/
> =

-------------- next part --------------
package Catalyst::Controller::FormBuilder::Multiple;

use strict;
use base qw| Catalyst::Controller::FormBuilder |;

sub __setup
{
  my $self =3D shift;
  my $class =3D ref $self;
  =

  # Get a copy of the template setting or use default
  # NOTE: Duplicated from parent, unsure of best way to do this cleanly
  my $config =3D $self->config->{'Controller::FormBuilder'} || {};
  my $tmpl_type =3D $config->{template_type} || "TT";
  =

  # Override the action value from the config to point to our template
  # actions, which will be passed on to the parent's setup method
  $config->{action} ||=3D "Catalyst::Controller::FormBuilder::Multiple::Act=
ion::$tmpl_type";
  =

  $self->SUPER::__setup();
}

1;
-------------- next part --------------
package MyApp::Controller::Test;

use strict;
use warnings;
use base 'Catalyst::Controller::FormBuilder::Multiple';

sub foo : Local Form
{
  my ( $self, $c ) =3D @_;
  my $foo_form =3D $self->formbuilder;
  my $foo_search_form =3D $c->forward('foo_search');
}

sub foo_search : Local Form
{
  my ( $self, $c ) =3D @_;
  my $form =3D $self->formbuilder;
  return $form;
}

1;
-------------- next part --------------
package Catalyst::Controller::FormBuilder::Multiple::Action::TT;

use strict;
use base qw| Catalyst::Controller::FormBuilder::Action::TT |;

sub setup_template_vars
{
  my $self =3D shift;
  my ( $controller, $c ) =3D @_; =

  =

  $self->SUPER::setup_template_vars(@_); =

  =

  # Get the name of the current form, and the stash and obj names that have=
 already
  # been created
  my $form_name  =3D $controller->_formbuilder->name;
  my $stash_name =3D $controller->_fb_setup->{stash_name};
  my $obj_name   =3D $controller->_fb_setup->{obj_name};
  =

  # If a form name is defined, create aliases to this form by name
  # NOTE: Will make multiple form hash key configurable later
  if ( defined $form_name )
  {
    $c->stash->{forms}{$form_name}{$stash_name} =3D $c->stash->{$stash_name=
};
    $c->stash->{forms}{$form_name}{$obj_name} =3D $c->stash->{$obj_name};
  }
  =

  # DEBUG, will remove later
  $c->log->debug("REAL ACTION: " . ( $self->_attr_params->[0] || $self->rev=
erse ) );
  $c->log->debug("ACTION: " . $c->action );
  $c->log->debug("FORM NAME: " . $form_name);
}

1;


More information about the Catalyst mailing list