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

Juan Camacho jc5826 at gmail.com
Wed Feb 14 12:53:04 GMT 2007


Doubt it has anything to do with your environment. I thought I had
tested it a while back when helping someone else, but maybe something
was overlooked since I never got a final word back from the guy I was
helping.  I think I have an idea of what might be wrong -- it has to
do with the following sequence of events:

Action foo
========
1) setup new FormBuilder before action
2) Run foo action which then $c->forwards to foo_search
    Action foo_search
   ==============
   1a) setup new FormBuilder before action
   1b) run foo_search action
   1c) setup_template_vars for foo_search after action
3) setup_template_vars for foo after action

Problem in #3 is that $self->_formbuilder is clobbered from the inner
forward action.

I will try to look into this today and get back to you, but it may not
be until quite late tonight and I won't be able to spend too much time
on it until this weekend.  In the mean time, send *me* directly a
zip/gz of a minimal MyApp catalyst application (including forms and tt
files) so I can quickly get going on it.

Hopefully others will chime in to provide other ideas and
clarification of the action sequence.


On 2/14/07, Danny Warren <danny at io.com> wrote:
> 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) = @_;
> >   # $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.org/
> > Dev site: http://dev.catalyst.perl.org/
> >
>
> package Catalyst::Controller::FormBuilder::Multiple;
>
> use strict;
> use base qw| Catalyst::Controller::FormBuilder |;
>
> sub __setup
> {
>   my $self = shift;
>   my $class = 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 = $self->config->{'Controller::FormBuilder'} || {};
>   my $tmpl_type = $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} ||= "Catalyst::Controller::FormBuilder::Multiple::Action::$tmpl_type";
>
>   $self->SUPER::__setup();
> }
>
> 1;
>
> package MyApp::Controller::Test;
>
> use strict;
> use warnings;
> use base 'Catalyst::Controller::FormBuilder::Multiple';
>
> sub foo : Local Form
> {
>   my ( $self, $c ) = @_;
>   my $foo_form = $self->formbuilder;
>   my $foo_search_form = $c->forward('foo_search');
> }
>
> sub foo_search : Local Form
> {
>   my ( $self, $c ) = @_;
>   my $form = $self->formbuilder;
>   return $form;
> }
>
> 1;
> package Catalyst::Controller::FormBuilder::Multiple::Action::TT;
>
> use strict;
> use base qw| Catalyst::Controller::FormBuilder::Action::TT |;
>
> sub setup_template_vars
> {
>   my $self = shift;
>   my ( $controller, $c ) = @_;
>
>   $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  = $controller->_formbuilder->name;
>   my $stash_name = $controller->_fb_setup->{stash_name};
>   my $obj_name   = $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} = $c->stash->{$stash_name};
>     $c->stash->{forms}{$form_name}{$obj_name} = $c->stash->{$obj_name};
>   }
>
>   # DEBUG, will remove later
>   $c->log->debug("REAL ACTION: " . ( $self->_attr_params->[0] || $self->reverse ) );
>   $c->log->debug("ACTION: " . $c->action );
>   $c->log->debug("FORM NAME: " . $form_name);
> }
>
> 1;
> _______________________________________________
> List: Catalyst at lists.rawmode.org
> Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/
> Dev site: http://dev.catalyst.perl.org/
>
>



More information about the Catalyst mailing list