Skip to content

Helpful Code Snippets

afresh1 edited this page Jan 29, 2012 · 14 revisions

Helpful Code Snippets

Cookbook example of using Mojolicious waypoint and bridge routes

Mojolicious has an extremely powerful routing model. The following is a cut and paste example of using the Mojolicious bridge and waypoint route methods. The full documentation for Mojolicious routes can be found at http://mojolicio.us/perldoc/Mojolicious/Guides/Routing. To run this cookbook example, paste the following code into your mojolicious application startup subroutine. Assuming your Mojolicious application is listening on http://localhost:3000, enter the following URL's into your browser after restarting Mojolicious.

/foo
/foo/bar
/foo/baz
/foo/bam
/foo/bam/groovy

Place these in your startup subroutine

my $r = $self->routes;

my $foo = $r->bridge('/foo')->to(cb => sub {
    my $self = shift;
    $self->stash(foo => 'I am /foo!' );
});

$foo->route('/bar')->to(cb => sub {
    my $self = shift;
    $self->render(text => 'I am /bar! ' . $self->stash('foo') );
});

$foo->route('/baz')->to(cb => sub {
    my $self = shift;
    $self->render(text => 'I am /baz ' . $self->stash('foo') );
});

my $bam = $foo->waypoint('/bam')->to(cb => sub {
    my $self = shift;
    $self->render(text => 'I am /bam ' . $self->stash('foo') );
});

$bam->route('/:myvar')->to(cb => sub {
    my $self = shift;
    $self->render(text => 'I am /bam ' . $self->stash('foo') .  $self->stash('myvar')  );
});

These examples use the callback feature of Mojolicious routes however, you can also use controllers and actions to set variables and "do stuff". The sky is the limit. Use your imagination and have fun!

Additional information on Mojolicious routes can be found at:

http://mojolicio.us/perldoc/Mojolicious/Guides/Routing

https://github.com/kraih/mojo/wiki/Routes-for-non-lite-apps

Execute arbitrary CODE on each page request

after_static_dispatch => sub { return if $_[0]->stash->{'mojo.rendered'}; CODE }

Loading sessions and checking authentication using bridges

This example has been more or less obsoleted since the existance of Mojolicious::Plugin::Authentication, which basically does all this for you, but I'll leave the example here if you want a DIY approach :)

This assumes you're using the Mojolicious::Plugin::Session plugin, backed by MojoX::Session

# place these two functions in a controller, assuming Auth.pm
sub check_session {
    my $self = shift;
    my $session = $self->stash->{'mojox-session'};
    if($session->load) {
        if($session->is_expired) {
            $session->flush;
            $session->create;
        } else {
            my $uid = $session->data('uid'); 
            my $user;
            if($uid && ($user = <load_your_user_here>)) {
                $self->stash->{'user'} = $user;
                $session->extend_expires;
                $session->flush;
            }
        }
    } else {
        $session->create;
        $session->flush;
    }
}
sub check_loggedin {
    my $self = shift;

    return 1 if($self->stash('user'));
    # either render a template, or redirect
    $self->render(template => 'auth/login') and return 0;
    #$self->redirect_to('/login') and return 0;
}

Then, in your main app file, you can do the following:

my $r = $self->routes->bridge('/')->to('auth#check_session');
my $routes_requiring_loggedin_user = $r->bridge('/')->to('auth#check_loggedin')

# login page/handler
$r->route('/auth/login')->to('auth#login');

# a profile page that needs ppl to be logged in
$routes_requiring_loggedin_user->route('/profile')->to('profile#index');

A good example of how to use waypoints

my $articles = $r->waypoint('/articles')->to('articles#list'); 

my $article = $articles->route('/:id')->to('#view');"

Playing with the before_render hook

This hook gives you the possibility to mess with your data before rendering takes place. Imagine the following:

sub foo { 
   my $self = shift;
   $self->stash(result => { ok => 1, message => 'Hi, I am Foo' });
}

Which is routed simply as: $r->route('/foo')->to('controller#foo');

Auto-rendering, a beautiful thing, will now merrily grab the template controller/foo.html.ep if you request this as /foo or /foo.html. Imagine that you also want this URL to respond to JSON requests properly, but you don't want to manually do the if-then-else dance to determine how to call render. Well, if you don't, the renderer will try to render /controller/foo.json.ep which isn't what you want.

Enter the before_render hook

$app->plugins->add_hook(before_render => sub {
  my $self = shift;
  my $controller = shift;
  my $args = shift;

  $controller->stash->{json} = delete($controller->stash->{result}) if($controller->stash->{format} eq 'json');  
})

And now, your app will "do the right thing". The json stash key is automatically seen and will render json; if you request anything else, it will go look for the proper template.

Now imagine you have per-user defaults that you want to set in the stash, $app-defaults> is nice for global (application wide) defaults, but per-user defaults are usually handled on a per-request basis; but here we go:

$app->plugins->add_hook(before_render => sub {
    my $self = shift;
    my $c = shift;
    my $args = shift;

    $c->stash->{user_colors} = $c->some_contrived_helper->get_user_colors;
});

Even more interesting things are most likely possible, but these two are the main reasons I'm pretty happy with the existance of this hook ;)

Clone this wiki locally