Search code examples
perlmojolicious

How to call a Mojolicious controller method after failing on template


I have a Mojolicious problem that I suspect has an easy solution, but I can't swim through all of its code.

$r->get(
    '/:controller/:action',
    sub {
        my $c = shift;
        $c->render_maybe && return;

       # No template. Either call controller->action() or dispatch as POST
    }
);
$r->post('/:controller/:action');

As you can see, I have two routes that use the same URL, one for GET and one for POST. The POST is straightforward. It renders after finding the controller and action method and isn't concerned with a template. I have the GET method working where a template exists, ignoring the controller, by using a callback with render_maybe(). My issue is, if there isn't a template, I want to go ahead and run the controller's method.

One solution would be to simply identify my controller and call the action. Since I'm using placeholders in my route, I can't simply hard code this. So, is there a Mojolicious way of getting my controller class, or actual code that will get the class and call the method? I have both controller and action defined in stash, so this really shouldn't be a big deal. Mojo knows how to do this internally.

Another option would be to convert this to a POST method and run it as normal. I don't know if it's best to either come up with the URL, or find the defined POST route, or just convert my GET to a POST. I'm not sure how to accomplish any of these.

Thanks.


Solution

  • I'm not sure if this is the intended use case for under(), but it seems to be a decent solution to my problem.

    $r->under( '/:controller/:action', sub { !shift->render_maybe } )->get('/');
    $r->post('/:controller/:action');
    

    Chaining under()->get() will create a nested route. The first in the stack will render a template, if it exists, from the render_maybe, stopping there. If the template doesn't exist, it will go to the standard get(), which will first check for a controller action. This is exactly what I was wanting.