How to stop rendering after user error?

142 views
Skip to first unread message

Peter Valdemar Mørch

unread,
Dec 1, 2016, 12:52:29 PM12/1/16
to Mojol...@googlegroups.com
Say in my controller I'm 5 levels deep and discover there is a problem with the user's input. I call:

    $c->render(
        template => 'errors/badValues',
        message => 'The value of foo cannot be "bar"',
    );

And now I want to stop the entire request right there. I guess the behaviour I'm looking for is that of an exception - return up the call stack - without having to do something with a return value and then

    callSub()
      or return;

at every stack level. So what I've done is create an exception type and

    $c->render(
        template => 'errors/badValues',
        message => 'The value of foo cannot be "bar"',
    );
    die(StopRenderingException->new());

And then in setup:

    $self->hook( around_dispatch => sub {
        my ( $next, $c ) = @_;
        eval {
            $next->();
        };
        if ($@) {
            my $err = $@;
            if (blessed($err) && $err->isa('StopRenderingException')) {
                return;
            } else {
                die $err;
            }
        }
    });

It does have a hacky smell to it though. Is there a better best-practice?

Peter

Alexbyk (subscriptions)

unread,
Dec 1, 2016, 1:38:45 PM12/1/16
to mojol...@googlegroups.com

Actually, you're on the right way. But instead of calling render in controller (you'll get many duplicates of the same code), you better just leave only "die" there, and call render method from the hook. Smthng like this:

# hook (you can also consider arount_action hook)
$self->hook(around_dispatch => sub ($next, $c) {
    eval { $next->(); 1 } or $c->render('bad/value', msg => $@);
});

# in controller
sub myaction($c) {
  die MyException->new() unless $c->stash('positive') > 0;
  ...
}


--
You received this message because you are subscribed to the Google Groups "Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mojolicious...@googlegroups.com.
To post to this group, send email to mojol...@googlegroups.com.
Visit this group at https://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/d/optout.

Jan Henning Thorsen

unread,
Dec 4, 2016, 8:52:11 AM12/4/16
to Mojolicious, Mojol...@googlegroups.com
I think this is code smell. There's probably a much better design pattern you can use, than using an exception to stop rendering. I would try my best to avoid this pattern and look for some other solution.

Paul Williams

unread,
Dec 16, 2016, 4:29:38 AM12/16/16
to Mojolicious, Mojol...@googlegroups.com
You could maybe try to implement something based on the docs http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Rendering-exception-and-not_found-pages

FYI, I found I had to implement something similar to you in the around_action hook for the occasions where a package I didn't have control of decided to die. In a production environment, having control over the exceptions is important, and I couldn't find a better pattern.

Paul Williams

unread,
Dec 16, 2016, 4:33:28 AM12/16/16
to Mojolicious, Mojol...@googlegroups.com
P.S. I did write https://metacpan.org/pod/Mojolicious::Plugin::ErrorsAndWarnings which I use to collect, well, errors and warnings during the request cycle. If you use this plugin and store your "bad values" in your different actions, you can then check the $c->errors() method in your before_render hook and return an appropriate response.


On Thursday, 1 December 2016 17:52:29 UTC, Peter Valdemar Mørch wrote:

Nuno Mota

unread,
Jun 15, 2018, 12:42:46 PM6/15/18
to Mojolicious
Did anyone find another solution for this?
Reply all
Reply to author
Forward
0 new messages