aristotle laid some criticism on CGI::Prototype based on heavy usage of it. Let's take his first criticism:
Its core idea is the "stay on this page or go to another" mechanism. This is directly in opposition to POST-redirect-GET and therefore to good HTTP style. I didn’t have to fight CGIP to do things properly, but I had to ignore its offerings and manually devise everything I needed.

stay or go

Yes, the core of CGI::Prototype is the activate function and what he says about stay or go is obvious if you look at the code:
sub activate { my $self = shift; eval { $self->prototype_enter; $self->app_enter; my $this_page = $self->dispatch; $this_page->control_enter; $this_page->respond_enter; my $next_page = $this_page->respond; ## STAY OR GO! $this_page->respond_leave; if ($this_page ne $next_page) { $this_page->control_leave; $next_page->control_enter; } $next_page->render_enter; $next_page->render; $next_page->render_leave; $next_page->control_leave; $self->app_leave; $self->prototype_leave; }; $self->error($@) if $@; # failed something, go to safe mode }

what is POST-redirect-GET

POST-redirect-GET is best explained by example. Let's say you are filling out a form and it posts to /register_user

What the webapp would do is store the POSTed data in the session stash and then issue a redirect to the same URL but via a GET, and most likely the GET would retrieve the session data and say "thank you for registering" or offer to confirm the entered data.

why is that cool?

To be honest, what I see is twice as many hits on my server just because someone did not want to call an in-memory function.

But I think the argument is that the GET form of /register_user could be used to present user registration data at many times based on query string data and other things. And so have a well-formed URL API to that rendering functionality is important. And if one resorted to functions, one might not separate the idea of storing a user versus displaying the results of such storage.

I get along just fine without POST-redirect-GET

Because CGI::Prototype is quite modular, the rendering of user registration is handled in a different model. So, after getting the POST data via one module (let's say User::Register), I then confirm it via another module (i.e. User::Register::Confirm) and the code the the User::Register module would have a  respond method that would return 'User::Register::Confirm' Here is actual code from a working CGI::Prototype website of mine... the respond method basically looks at the form data and either confirms the signup or makes the user redo... and all without using redirects:
sub respond { my $self = shift; my $results = Data::FormValidator->check( $self->CGI, $dfv_profile ) +; my $response_page; if ( $results->has_missing() || $results->has_invalid() ) { $response_page = 'Gimble::Page::Signup::Redo'; eval "require $response_page"; $response_page->reflect->addSlots( results => $results ); } else { $response_page = $self; } return $response_page; }

Which do you like and why

Feel free to tell me how you would do this in your favorite framework. We dont hear enought about Jifty these days... wha about Mojo, Catalyst... share your ideas on this topic.

Replies are listed 'Best First'.
Re: CGI::Prototype criticism 1 - cannot use POST-redirect-GET paradigm
by Jenda (Abbot) on Dec 19, 2008 at 22:45 UTC

    I think you have the POST-redirect-GET wrong. The point is not to "avoid calling an in-memory function" (whatever that is). The point is to do whatever action you need with the posted data and then redirect the user to a different page. So that if all this goes well, the user may refresh that page as many times as he/she wants without the danger of posting the same data again and accidentally submitting yet another order or yet another posting.

    If you stick all the data to the session or somewhere, redirect the user and process the data only once you receive the GET request, you've just killed any reason to do the redirection.

    IMHO, of course.

Re: CGI::Prototype criticism 1 - cannot use POST-redirect-GET paradigm
by jeffa (Bishop) on Dec 19, 2008 at 17:01 UTC

    I tend to make "mini MVC's" with Mason. I find that overabstraction leads to the exact inverse of what you are trying to avoid -- redundant code. And that inverse is a God object that tries to do everything for everybody. So, what i do from time to time is create a top level component that handles CRUD, so my update sub would first call a custom validation sub located in the same package. I set up a messaging system so that if a user enter invalid data, they see the same form with their error messages so they may correct and resubmit. I determine what the "response page" is by calling the proper component. If they entered valid data, that component is the list view. If not, that component is the add_update view again.

    This method has worked very well for -- giving me enough abstraction to make laborious tasks more fun while not being too rigid that i have to readdress my design over and over. Here is the update() method of one of these "objects" :

    sub update { my %args = @_; my @messages = (); my @errors = validate_args( %args ); if (@errors) { # package the errors up as error messages @messages = map {{ class => 'error', data => $_ }} @errors; # override landing page back to update so user can fix errors # $comp is set to 'list' prior to this method call $comp = 'update'; } else { my $sth = $dbh->prepare(' UPDATE thingy SET foo = ?, bar = ? WHERE id = 1 '); $sth->execute( $args{foo}, $args{bar}, ); push( @messages, { class => 'message', data => 'Thingy successfully updated.' } ); } return @messages; }

    This method is called by a dispatcher which then determines what to fetch:

    $m->comp( "comps/thingy/$comp.md", messages => \@messages, %ARGS );
    For every CRUD method in the "object" there is a corresponding Mason component that acts as the "template." I try to treat these component like HTML::Template templates -- only variable substitutions, conditions and loops -- but i will throw in display code from time to time like TT would allow me to do.

    I hope this adds to the conversation -- I kinda missed what the point was. :/

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: CGI::Prototype criticism 1 - cannot use POST-redirect-GET paradigm
by zby (Vicar) on Dec 19, 2008 at 14:56 UTC
    Personally I avoid modules with no new versions for more than two years. This not a strict rule - but the perl web-framework field seems to be very competetive recently - so in this case I would rather stick to it.
      So you're going to downgrade something that is stable, and is being used for commercial sites as we speak, simply because there are no significant outstanding bugs to fix (other than a bit of windows testing patches), and instead opt for things that are either buggy or not complete, and therefore have recent releases?

      Ok, your choice. But not one I would make. My clients using CGIP are happy. That's all.

        My mistake - I was thinking about choosing a library for new projects - not about continuing old ones. I should have made it clear.
        It don't fit!