[Catalyst-commits] r8832 -
trunk/examples/CatalystAdvent/root/2008/pen
matthewt at dev.catalyst.perl.org
matthewt at dev.catalyst.perl.org
Thu Dec 11 23:58:38 GMT 2008
Author: matthewt
Date: 2008-12-11 23:58:37 +0000 (Thu, 11 Dec 2008)
New Revision: 8832
Added:
trunk/examples/CatalystAdvent/root/2008/pen/11.pod
Log:
11.pod
Added: trunk/examples/CatalystAdvent/root/2008/pen/11.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2008/pen/11.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2008/pen/11.pod 2008-12-11 23:58:37 UTC (rev 8832)
@@ -0,0 +1,131 @@
+=head1 Doing rails-style routes with Catalyst
+
+People often ask about using rails-style routes, and why Catalyst doesn't
+"support" them. Well, actually, it does - through the magic of config.
+
+=head1 Routes via the config file
+
+The key is this: action attributes are actually just defaults - when you do
+
+ sub foo :Local {
+
+that makes the default attribute hash for foo { Local => [ '' ] }. Well,
+it doesn't, because Local is parsed - what you actually get for
+
+ package MyApp::Controller::Name;
+
+ sub foo :Local {
+
+is { Path => [ 'name/foo' ] }. Now, this can be overriden from the config
+file by doing something like:
+
+ <Controller Name>
+ <action foo>
+ Path somewhere/else
+ </action>
+ </Controller>
+
+Which is perhaps a little bit verbose, but then you only use config for
+per-deployment stuff, right? Right?
+
+=head1 Routes via code, and controller reuse
+
+So doing it from MyApp.pm is maybe a bit cleaner -
+
+ __PACKAGE__->config(
+ Controller => {
+ Name => {
+ actions => {
+ foo => { Path => 'somewhere/else' }
+ }
+ }
+ }
+ );
+
+alhtough this is still quite verbose, of course. Generally, this approach is
+only ever used to allow URL localisations - for example if you sell a white
+label app to a foreign client you can change the URL parts to their language;
+I'm aware of people having done this in production.
+
+Of course, the other thing you can do is to use this to make reusable
+controllers -
+
+ package MyApp::ControllerBase::List;
+
+ sub list :Args(0) {
+ my ($self, $c) = @_;
+ my $rs = $c->stash->{rs}->page($c->req->query_params->{page}||1);
+ $c->stash(
+ pager => $rs->pager,
+ results => [ $rs->all ]
+ );
+ }
+
+ package MyApp::Controller::Thingies;
+
+ use base qw(MyApp::ControllerBase::List);
+
+ __PACKAGE__->config(
+ actions => {
+ list => { Chained => 'load_thingies' }
+ }
+ );
+
+ sub load_thingies :Chained('/') :CaptureArgs(0) :PathPart('thingies') {
+ my ($self, $c) = @_:
+ $c->stash(
+ rs => $c->model('DB::Thingy')
+ );
+ }
+
+and now Thingies->list will be chained off Thingies->load_thingies.
+
+=head1 Syntactic sugar
+
+But we were talking about routes, weren't we? Though I would observe that
+controllers' self-contained-ness is what makes this sort of subclass-to-reuse
+stuff possible; the rails guys say "re-use in the large is overrated", we
+say "well, actually, it's bloody hard, but if you're careful ...". Anyway.
+
+Let's see if we can't make routes a bit prettier.
+
+ {
+
+ my %config;
+
+ sub routes (&) {
+ my $cr = $_[0];
+ %config = ();
+ $cr->();
+ __PACKAGE__->config(\%config);
+ }
+
+ sub route {
+ my ($path, $to) = @_;
+ my ($controller, $action) = split(/->/, $to);
+ $config{"Controller::$controller"}{actions}{$action}{Path} = [ $path ];
+ }
+
+ sub to { @_ }
+ }
+ use namespace::clean; # this will get rid of the subs on EOF
+
+ routes {
+ route 'some/path' to 'Name->foo';
+ };
+
+and the end result will be (provided we've marked foo as an action via
+
+ sub foo :Action {
+
+) that /some/path will dispatch to that method on MyApp::Controller::Name.
+
+Of course, I still think that Catalyst's self-contained controller approach
+is better, but if you really want routes, please consider the code above as
+under the same license as perl and send CatalystX::Routes to the CPAN :)
+
+-- mst
+
+=head1 AUTHOR
+
+Matt S Trout C<< <mst at shadowcat.co.uk> >> ( http://www.shadowcat.co.uk/ )
More information about the Catalyst-commits
mailing list