2012 Feed

uri_for

OX - 2012-12-09

Paths and actions

Different pages of your application need to be able to reference each other, and doing this by hardcoding URL paths is fairly fragile. URLs are the external API to your application, and may need to change for all kinds of different reasons, including things like SEO and general aesthetics which are frequently dictated by the client. Tying any part of your application's functionality to URL paths themselves is a good way to make the application hard to modify as time goes on.

What we need is a way to refer to application endpoints using an internal identifier instead of an external one (the old adage "All problems in computer science can be solved by another level of indirection" comes to mind). That way, we can change our external URLs without having to modify much, if any, application code. Luckily, we already have one. Yesterday we saw how you could access the mapping for the current route via $r->mapping. The inverse operation of $r->mapping is $r->uri_for. uri_for takes a mapping hashref and returns the URI path corresponding to that mapping.

For instance, given these routes:


1: 
2: 
3: 
4: 
5: 

 

route '/' => 'root.index';
route '/view/:id' => 'root.view';
route '/admin/view/:id' => 'root.view', (
    section => 'admin',
);

 

we get this:


1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 

 

# "/"
say $r->uri_for({
    controller => 'root',
    action => 'index',
});

# "/view/123"
say $r->uri_for({
    controller => 'root',
    action => 'index',
    id => 123,
});

# "/admin/view/123"
say $r->uri_for({
    controller => 'root',
    action => 'index',
    id => 123,
    section => 'admin',
});

 

Additionally, you only have to specify enough of the mapping to make it unique. For instance, if the three routes listed above were the only routes in the application, $r->uri_for({ section => 'admin', id => 123 }) would also be sufficient for OX to figure out that you want "/admin/view/123".

The name entry

This can still be a bit verbose though, so there is a shorthand to make the common case easier. If you pass in just a single string to uri_for, it will be treated as though you passed a mapping with that string as the name value. This allows you to give the various routes in your application unique (and meaningful) names, and access them easily. If you say:


1: 
2: 
3: 
4: 

 

route '/' => 'root.index';
route '/about' => 'root.about', (
    name => 'about',
);

 

then you can use $r->uri_for('about') to access the "/about" page.

In addition, the ControllerAction and HTTPMethod route builders also by default set the name value to be the action spec. This means that in the previous example, $r->uri_for('root.index') can also be used to access the "/" path.

Gravatar Image This article contributed by: Jesse Luehrs <jesse.luehrs@iinteractive.com>