Catalyst-Manual
view release on metacpan or search on metacpan
lib/Catalyst/Manual/Cookbook.pod view on Meta::CPAN
<a href="[% c.uri_for('/login') %]">Login Here</a>
Although the parameter starts with a forward slash, this is relative
to the application root, not the webserver root. This is important to
remember. So, if your application is installed at
C<http://www.domain.com/Calendar>, then the link would be
C<http://www.mydomain.com/Calendar/Login>. If you move your application
to a different domain or path, then that link will still be correct.
Likewise,
<a href="[% c.uri_for('2005','10', '24') %]">October, 24 2005</a>
The first parameter does NOT have a forward slash, and so it will be
relative to the current namespace. If the application is installed at
C<http://www.domain.com/Calendar>. and if the template is called from
C<MyApp::Controller::Display>, then the link would become
C<http://www.domain.com/Calendar/Display/2005/10/24>.
If you want to link to a parent uri of your current namespace you can
prefix the arguments with multiple 'C<../>':
<a href="[% c.uri_for('../../view', stashed_object.id) %]">User view</a>
Once again, this allows you to move your application around without
having to worry about broken links. But there's something else, as
well. Since the links are generated by C<uri_for>, you can use the same
template file by several different controllers, and each controller
will get the links that its supposed to. Since we believe in Don't
Repeat Yourself, this is particularly helpful if you have common
elements in your site that you want to keep in one file.
Further Reading:
L<Catalyst>
L<Catalyst::View::TT>
L<Template>
=head2 Adding RSS feeds
Adding RSS feeds to your Catalyst applications is simple. We'll see two
different approaches here, but the basic premise is that you forward to
the normal view action first to get the objects, then handle the output
differently.
=head3 Using L<XML::Feed>
Assuming we have a C<view> action that populates
'entries' with some L<DBIx::Class> iterator, the code would look something
like this:
sub rss : Local {
my ($self,$c) = @_;
$c->forward('view'); # get the entries
my $feed = XML::Feed->new('RSS');
$feed->title( $c->config->{name} . ' RSS Feed' );
$feed->link( $c->req->base ); # link to the site.
$feed->description('Catalyst advent calendar'); Some description
# Process the entries
while( my $entry = $c->stash->{entries}->next ) {
my $feed_entry = XML::Feed::Entry->new('RSS');
$feed_entry->title($entry->title);
$feed_entry->link( $c->uri_for($entry->link) );
$feed_entry->issued( DateTime->from_epoch(epoch => $entry->created) );
$feed->add_entry($feed_entry);
}
$c->res->body( $feed->as_xml );
}
With this approach you're
pretty sure to get something that validates.
Note that for both of the above approaches, you'll need to set the
content type like this:
$c->res->content_type('application/rss+xml');
=head3 Final words
You could generalize the second variant easily by replacing 'RSS' with a
variable, so you can generate Atom feeds with the same code.
Now, go ahead and make RSS feeds for all your stuff. The world *needs*
updates on your goldfish!
=head2 Forcing the browser to download content
Sometimes you need your application to send content for download. For
example, you can generate a comma-separated values (CSV) file for your
users to download and import into their spreadsheet program.
Let's say you have an C<Orders> controller which generates a CSV file
in the C<export> action (i.e., C<http://localhost:3000/orders/export>):
sub export : Local Args(0) {
my ( $self, $c ) = @_;
# In a real application, you'd generate this from the database
my $csv = "1,5.99\n2,29.99\n3,3.99\n";
$c->res->content_type('text/comma-separated-values');
$c->res->body($csv);
}
Normally the browser uses the last part of the URI to generate a
filename for data it cannot display. In this case your browser would
likely ask you to save a file named C<export>.
Luckily you can have the browser download the content with a specific
filename by setting the C<Content-Disposition> header:
my $filename = 'Important Orders.csv';
$c->res->header('Content-Disposition', qq[attachment; filename="$filename"]);
Note the use of quotes around the filename; this ensures that any
spaces in the filename are handled by the browser.
( run in 1.821 second using v1.01-cache-2.11-cpan-5837b0d9d2c )