Search code examples
perlmojolicious

Bridge handler can't access stash data


I have the following code in our webapp written using Mojolicious, and it doesn't work as expected: the bridge handler doesn't get the correct stash data derived from routes (gets undef), so the rest of code fails, however, debug output of $self->stash('city') in any of route handlers is as expected.


...
# Router.
my $r = $self->routes->bridge->to('Main#common');
$r->route('/')->to('Main#index')->name('start');
$r->route('/:region/:city/category/:id')->to('Main#list_category')->name('list_category');
$r->route('/:region/:city/part/:id/:name')->to('Main#show_part')->name('show_part');
...
# Controller.
sub common
{
    my $self=shift;
    my $db=$self->db;
    my $city=$self->stash('city');
    my $region=$self->db->selectrow_hashref('select * from region where LOWER(translit)=? ORDER BY region_id LIMIT 1',undef,$city);
    say "City=$city.";
    if(!$region)
    {
        $region={};
    }
    $self->stash(region=>$region);
    return 1;
}
...

Solution

  • I think it's correct behavior.
    Look at this code. Placeholder is added when the appropriate route is taken to the processing, i.e., step by step.

    Really, look at you routes.

    my $r = $self->routes->bridge->to('Main#common');
    $r->route('/')->to('Main#index')->name('start');
    $r->route('/:region/:city/category/:id')->to('Main#list_category')->name('list_category');
    $r->route('/:region/:city/part/:id/:name')->to('Main#show_part')->name('show_part');
    

    I can't understand what behavior you expect when go to route /. Sub common will be invoked in this case. There are no value for placeholder city!

    So, correct solution for your routes must look like this:

    my $r = $self->routes;
    $r->route('/')->to('Main#index')->name('start');
    
    my $r_city = $r->bridge('/:region/:city/')->to('Main#common');
    $r_city->route('/category/:id')->to('Main#list_category')->name('list_category');
    $r_city->route('/part/:id/:name')->to('Main#show_part')->name('show_part');
    

    By the way,

    starting from Mojolicious version 6.0 bridge was deprecated to favor under. So, you need to replace bridge on under.

    But, if you very-very want to have value of placeholder city in common function, you may look at this two line.
    You need to write this BAD code in common sub:

    sub common {
      my $self = shift;
      my $stack = $self->match->stack;
      warn $self->dumper($stack);
      ...
    }
    

    Print $stack and you understand how to get value of placeholder city.