So I am trying to get a URL that looks like this: http://localhost:3000/admin/itemtype/32/edit
Instead, I am getting URLs that look like: http://localhost:3000/admin/itemtype/edit/32
In my template, I tried this: [% c.uri_for( 'edit', [ item_type.type_id ]) %]
which gave me the latter URL. If I do this: [% c.uri_for(c.controller('Admin::ItemType').action_for('edit'), [item_type.type_id] ) %]
I get what I want, but it seems too clunky to be doing in my view. Is there a simpler way to write that and have it still work? It seems like too common a thing to not have there be a simpler way, but I am just not finding it.
You might want to look at chained actions: Catalyst::DispatchType::Chained.
That gives you an easy way to have URIs like
/user/$userid/entries/$year/$month
And you can set the URI via:
my $action = $ctx->controller('Foo')->action_for('edit');
my $uri = $ctx->uri_for($action, \@captures, @arguments);
What goes into captures and what into arguments depends on your application design.
While the version of uri_for() that uses an action object instead of a string seems a bit more work, it gives you one huge advantage: If you change your application's URIs later on (imagine wanting to move
If you just want to type less, it might be the simplest thing to build yourself a utility method. One possibility would be to do this in a controller subclass:
sub uri_closure_for {
my ($self, $ctx, $action) = @_;
my $action_obj = $self->action_for($action);
return sub {
$ctx->uri_for($action_obj, @_);
};
}
and in the actual controller you could do:
sub foo :
... {
my ($self, $ctx) = @_;
$ctx->stash(make_edit_uri => $self->uri_closure_for('edit'));
}
and then in the template
[% make_edit_uri([2, 3], 4) %]
where [2, 3]
would be the captures and the 4
would be the argument.
HTH, phaylon
PS: Note that the code is just quickly hacked up and untested, of course.
From MyApp.pm
:
sub uri_for {
my $c = shift;
my ( $path ) = @_;
if ( not Scalar::Util::blessed( $path ) and 'ARRAY' eq ref $path ) {
my $action_path = shift @$path;
unshift @_, $action_cache->{ $action_path } ||= $c->dispatcher->get_action_by_path( $action_path );
$path = $_[0];
}
return URI::WithBase::Rel->new( $c->NEXT::uri_for( @_ ), $c->req->uri );
}
With that, you can write your second example like this:
[% c.uri_for(['/admin/itemtype/edit, item_type.type_id]) %]
Re:Excerpt from $work
Aristotle on 2009-03-19T20:46:57
Woops, that would be:
sub uri_for {
my $c = shift;
my ( $path ) = @_;
if ( not Scalar::Util::blessed( $path ) and 'ARRAY' eq ref $path ) {
my $action_path = shift @$path;
unshift @_, $c->dispatcher->get_action_by_path( $action_path );
$path = $_[0];
}
return URI::WithBase::Rel->new( $c->NEXT::uri_for( @_ ), $c->req->uri );
}(The actual method in our source is much more complicated since it also caches a bunch of things and papers over a few misbehaviours in the Cat dispatcher.)