Search code examples
perlmojolicious

Problem getting Mojolicious routes to work


The following route definition works nicely

sub load_routes {
 my($self) = @_;

 my $root = $self->routes;

 $root->get('/')->to(                 controller=>'Snipgen', action=>'indexPage');
 $root->any('/Snipgen')          ->to(controller=>'Snipgen', action=>'SnipgenPage1');
 $root->any('/Snipgen/show')     ->to(controller=>'Snipgen', action=>'SnipgenPage2');
 }

and "./script/snipgen.pl routes -v" gives

/              ....  GET               ^
/Snipgen       ....  *    Snipgen      ^\/Snipgen
/Snipgen/show  ....  *    Snipgenshow  ^\/Snipgen\/show

but this fails for 'http://127.0.0.1:3000/Snipgen/' giving page not found

sub load_routes {
 my($self) = @_;

 my $root = $self->routes;

 $root->get('/')->to(controller=>'Snipgen', action=>'indexPage');
 my $myaction = $root->any('/Snipgen')->to(controller=>'Snipgen', action=>'SnipgenPage1');
 $myaction->any('/show')              ->to(controller=>'Snipgen', action=>'SnipgenPage2');
 }

and the corresponding "./script/snipgen.pl routes -v" gives

/         ....  GET           ^
/Snipgen  ....  *    Snipgen  ^\/Snipgen
  +/show  ....  *    show     ^\/show

The SnipgenPageXX subs all have 'return;' as their last line. Any idea what is going wrong?


Solution

  • Mojolicious documentation states, that A route with children can't match on its own . You can work around this by adding a child route with '/'. Another option is to use under() which offers more control by adding a dispatch target for the partial route. As suggested in the comments by brian d foy, you can display the routes of your app by passing a routes option to your application script like so: perl -Ilib script/my_app routes -v. See the documentation here and here. The Mojolicious page not found template also displays your routes at the top of the page.

    You want the routes to look like this:

    /         ....  *           ^
    /Snipgen  ....  *  Snipgen  ^\/Snipgen
      +/      ....  *           ^
      +/show  ....  *  show     ^\/show
    

    Instead of:

    /         ....  *           ^
    /Snipgen  ....  *  Snipgen  ^\/Snipgen
      +/show  ....  *  show     ^\/show
    

    Adding a child with '/':

    sub load_routes {
        my($self) = @_;
    
        my $root = $self->routes;
    
        $root->any('/')->to(controller=>'Snipgen', action=>'indexPage');
        my $myaction = $root->any('/Snipgen')->to(controller => 'Snipgen');;
        $myaction->any('/')->to( action=>'SnipgenPage1');
        $myaction->any('/show')->to( action=>'SnipgenPage2');
    }
    

    Using under()

    sub load_routes {
        my($self) = @_;
    
        my $root = $self->routes;
    
        $root->get('/')->to(controller=>'Snipgen', action=>'indexPage');
        my $myaction = $root->under('/Snipgen');#->to('Auth#check')
        $myaction->any('/')->to(controller=>'Snipgen', action=>'SnipgenPage1');
        $myaction->any('/show')->to(controller=>'Snipgen', action=>'SnipgenPage2');
    }
    

    Or add a child route like so:

    sub load_routes {
        my($self) = @_;
        my $root = $self->routes;
        
        $root->get('/')->to(controller=>'Snipgen', action=>'indexPage');
        my $myaction = $root->get('Snipgen')
            ->to(controller=>'Snipgen', action=>'SnipgenPage1')
               ->add_child(Mojolicious::Routes::Route->new);
        $myaction->get('show')->to(controller=>'Snipgen', action=>'SnipgenPage2');
    }