Add a "negative" test to confirm that test02 does not have an admin create link
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 03_MoreCatalystBasics.pod
index 208b02c..5332811 100644 (file)
@@ -91,11 +91,13 @@ tutorial or in a directory that already has a "MyApp" subdirectory):
     created "MyApp/root"
     ...
     created "MyApp/script/myapp_create.pl"
+    Change to application directory and Run "perl Makefile.PL" to make sure your install is complete
     $ cd MyApp
 
 This creates a similar skeletal structure to what we saw in Chapter 2 of
 the tutorial, except with C<MyApp> and C<myapp> substituted for
-C<Hello> and C<hello>.
+C<Hello> and C<hello>.  (As noted in Chapter 2, omit the ".pl" from 
+the command if you are using Strawberry Perl.)
 
 
 =head1 EDIT THE LIST OF CATALYST PLUGINS
@@ -119,15 +121,31 @@ Enables the Catalyst debug output you saw when we started the
 C<script/myapp_server.pl> development server earlier.  You can remove
 this item when you place your application into production.
 
-As you may have noticed, C<-Debug> is not a plugin, but a I<flag>. 
+To be technically correct, it turns out that C<-Debug> is not a plugin, but a I<flag>. 
 Although most of the items specified on the C<__PACKAGE__-E<gt>setup> 
 line of your application class will be plugins, Catalyst supports a 
 limited number of flag options (of these, C<-Debug> is the most 
 common).  See the documentation for C<Catalyst.pm> to get details on 
 other flags (currently C<-Engine>, C<-Home>, and C<-Log>).
 
-If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
-messages.
+If you prefer, there are several other ways to enable debug output:
+
+=over 4
+
+=item *
+
+Use the C<$c-E<gt>debug> method
+
+=item *
+
+The C<-d> option to C<script/myapp_server.pl>
+
+=item *
+
+The C<CATALYST_DEBUG=1> environment variable (or set it to
+zero to templorarily disable debug output).
+
+=back
 
 B<TIP>: Depending on your needs, it can be helpful to permanently
 remove C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option
@@ -189,7 +207,8 @@ your I<application class>) and delete the lines with:
 Then replace it with:
 
     # Load plugins
-    use Catalyst qw/-Debug
+    use Catalyst qw/
+                    -Debug
                     ConfigLoader
                     Static::Simple
                 
@@ -213,8 +232,8 @@ L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your
 browser, not in the console window from which you're running your 
 application, which is where logging output usually goes.
 
-Make sure that when adding new plugins that you include them as a new
-dependancies within the Makefile.PL file. For example, after adding
+Make sure when adding new plugins you also include them as a new
+dependancy within the Makefile.PL file. For example, after adding
 the StackTrace plugin the Makefile.PL should include the following
 line:
 
@@ -239,10 +258,9 @@ during development.
 
 =item *
 
-When specifying plugins on the C<__PACKAGE__-E<gt>setup> line, you can 
-omit C<Catalyst::Plugin::> from the name.  Additionally, you can 
-spread the plugin names across multiple lines as shown here, or place 
-them all on one (or more) lines as with the default configuration.
+When specifying plugins, you can omit C<Catalyst::Plugin::> from the 
+name.  Additionally, you can spread the plugin names across multiple 
+lines as shown here or place them all on one line.
 
 =back
 
@@ -314,7 +332,7 @@ Controllers use one of five action types:
 =item *
 
 B<:Private> -- Use C<:Private> for methods that you want to make into 
-an action, but you do not want Catalyst to directly expose  
+an action, but you do not want Catalyst to directly expose  the method 
 to your users.  Catalyst will not map C<:Private> methods to a URI. 
 Use them for various sorts of "special" methods (the C<begin>, 
 C<auto>, etc. discussed below) or for methods you want to be able to 
@@ -350,11 +368,11 @@ controller down through the most specific class>.
 B<:Path> -- C<:Path> actions let you map a method to an explicit URI 
 path.  For example, "C<:Path('list')>" in 
 C<lib/MyApp/Controller/Books.pm> would match on the URL 
-C<http://localhost:3000/books/list> but "C<:Path('/list')>" would match 
-on C<http://localhost:3000/list>.  You can use C<:Args()> to specify 
-how many arguments an action should accept.  See 
-L<Catalyst::Manual::Intro/Action_types> for more information and a few 
-examples.
+C<http://localhost:3000/books/list>, but "C<:Path('/list')>" would 
+match on C<http://localhost:3000/list> (because of the leading slash). 
+You can use C<:Args()> to specify how many arguments an action should 
+accept.  See L<Catalyst::Manual::Intro/Action_types> for more 
+information and examples.
 
 =item *
 
@@ -405,34 +423,11 @@ L<HTML::Template> (L<http://html-template.sourceforge.net>).
 
 =head2 Create a Catalyst View
 
-When using TT for the Catalyst view, there are two main helper scripts:
-
-=over 4
-
-=item *
-
-L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
-
-=item *
-
-L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
-
-=back
-
-Both helpers are similar. C<TT> creates the C<lib/MyApp/View/TT.pm>
-file and leaves the creation of any hierarchical template organization
-entirely up to you. (It also creates a C<t/view_TT.t> file for testing;
-test cases will be discussed in Chapter 8.) C<TTSite>, on the other hand, 
-creates a modular and hierarchical view layout with
-separate Template Toolkit (TT) files for common header and footer
-information, configuration values, a CSS stylesheet, and more.
-
-While C<TTSite> was useful to bootstrap a project, its use is now
-deprecated and it should be considered historical.  For most Catalyst
-applications it adds redundant functionality and structure; many in the
-Catalyst community recommend that it's easier to learn both Catalyst and
-Template Toolkit if you use the more basic C<TT> approach.
-Consequently, this tutorial will use "plain old TT."
+When using TT for the Catalyst view, the main helper script
+is L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>.
+You may also come across references to 
+L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>,
+but its use is now deprecated.
 
 Enter the following command to enable the C<TT> style of view
 rendering for this tutorial:
@@ -471,14 +466,15 @@ And update it to match:
 B<NOTE:> Make sure to add a comma after '.tt2' outside the single
 quote.
 
-This changes the default extension for Template Toolkit from '.tt' to
-'.tt2' and changes the base directory for your template files from
-C<root> to C<root/src>.  These changes from the default are done mostly
-to facilitate the application we're developing in this tutorial; as with
-most things Perl, there's more than one way to do it...
+This changes the default extension for Template Toolkit from '.tt' to 
+'.tt2' and changes the base directory for your template files from 
+C<root> to C<root/src>.  Stick with these conventions for the 
+tutorial, but feel free to use whatever options you desire in your 
+applications (as with most things Perl, there's more than one way to 
+do it...).
 
 B<Note:> We will use C<root/src> as the base directory for our 
-template files, which a full naming convention of 
+template files, with a full naming convention of 
 C<root/src/_controller_name_/_action_name_.tt2>.  Another popular option is to
 use C<root/> as the base (with a full filename pattern of 
 C<root/_controller_name_/_action_name_.tt2>).
@@ -520,21 +516,25 @@ C<book> model object and prints the C<title> and C<rating> fields.
 The C<[%> and C<%]> tags are used to delimit Template Toolkit code.  TT
 supports a wide variety of directives for "calling" other files,
 looping, conditional logic, etc.  In general, TT simplifies the usual
-range of Perl operators down to the single dot (C<.>) operator.  This
+range of Perl operators down to the single dot (".") operator.  This
 applies to operations as diverse as method calls, hash lookups, and list
 index values (see
 L<http://search.cpan.org/perldoc?Template::Manual::Variables> for
-details and examples).  In addition to the usual C<Template> module Pod
+details and examples).  In addition to the usual L<Template> module Pod
 documentation, you can access the TT manual at
 L<http://search.cpan.org/perldoc?Template::Manual>.
 
-B<TIP:> While you can build all sorts of complex logic into your TT
-templates, you should in general keep the "code" part of your templates
-as simple as possible.  If you need more complex logic, create helper
-methods in your model that abstract out a set of code into a single call
-from your TT template.  (Note that the same is true of your controller
-logic as well -- complex sections of code in your controllers should
-often be pulled out and placed into your model objects.)
+B<TIP:> While you can build all sorts of complex logic into your TT 
+templates, you should in general keep the "code" part of your 
+templates as simple as possible.  If you need more complex logic, 
+create helper methods in your model that abstract out a set of code 
+into a single call from your TT template.  (Note that the same is true 
+of your controller logic as well -- complex sections of code in your 
+controllers should often be pulled out and placed into your model 
+objects.)  In Chapter 4 of the tutorial we will explore some extremely 
+helpful and powerful features of L<DBIx::Class> that allow you to pull 
+code out of your views and controllers and place it where it 
+rightfully belongs in a model class.
 
 
 =head2 Test Run The Application
@@ -553,7 +553,7 @@ model working below.
 
 If you run into problems getting your application to run correctly, it
 might be helpful to refer to some of the debugging techniques covered in
-the L<Debugging|Catalyst::Manual::Tutorial::07_Debugging> part of the
+the L<Debugging|Catalyst::Manual::Tutorial::07_Debugging> chapter of the
 tutorial.
 
 
@@ -648,13 +648,13 @@ required if you do a single SQL statement on the command line).  Use
 your OS command prompt.
 
 Please note that here we have chosen to use 'singular' table names. This
-is because the default inflection code for L<DBIx::Class:Schema::Loader>
+is because the default inflection code for L<DBIx::Class::Schema::Loader>
 does NOT handle plurals. There has been much philosophical discussion
 on whether table names should be plural or singular. There is no one
 correct answer, as long as one makes a choice and remains consistent
 with it. If you prefer plural table names (e.g. they are easier and
 more natural to read) then you will need to pass it an inflect_map 
-option. See L<DBIx::Class:Schema::Loader> for more information.
+option. See L<DBIx::Class::Schema::Loader> for more information.
 
 For using other databases, such as PostgreSQL or MySQL, see 
 L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices>.
@@ -664,7 +664,7 @@ L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices>.
 
 Catalyst can be used with virtually any form of datastore available 
 via Perl.  For example, L<Catalyst::Model::DBI|Catalyst::Model::DBI> 
-can be used to access databases through the traditional Perl C<DBI> 
+can be used to access databases through the traditional Perl L<DBI> 
 interface or you can use a model to access files of any type on the 
 filesystem.  However, most Catalyst applications use some form of 
 object-relational mapping (ORM) technology to create objects 
@@ -690,18 +690,20 @@ running this command:
 
     $ perl -MCatalyst::Model::DBIC::Schema -e \
         'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.23
+    0.31
 
-(please note that the '\' above is a line continuation marker and
-should NOT be included as part of the command)
+Please note the '\' above.  Depending on your environment, you might 
+be able to cut and paste the text as shown or need to remove the '\' 
+character to that the command is all on a single line.
 
-If you don't have version 0.23 or higher, please run this command
-to install it directly from CPAN:
+You should have version 0.31 or greater if you are following along 
+with Debian 5.  In other environments, you may need to run this 
+command to install it directly from CPAN:
 
     $ sudo cpan Catalyst::Model::DBIC::Schema
 
 And re-run the version print command to verify that you are now at 
-0.23 or higher.
+0.31 or higher.
 
 
 =head2 Create Static DBIx::Class Schema Files
@@ -713,7 +715,7 @@ L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> and
 automatically build the required files for us:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
+        create=static dbi:SQLite:myapp.db
      exists "/home/me/MyApp/script/../lib/MyApp/Model"
      exists "/home/me/MyApp/script/../t"
     Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
@@ -721,8 +723,9 @@ automatically build the required files for us:
     created "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
     created "/home/me/MyApp/script/../t/model_DB.t"
 
-(please note that the '\' above is a line continuation marker and
-should NOT be included as part of the command)
+Please note the '\' above.  Depending on your environment, you might 
+be able to cut and paste the text as shown or need to remove the '\' 
+character to that the command is all on a single line.
 
 The C<script/myapp_create.pl> command breaks down like this:
 
@@ -751,11 +754,6 @@ into files.
 
 =item *
 
-C<components=TimeStamp> causes the help to include the 
-L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp> DBIC component.
-
-=item *
-
 And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
 for use with SQLite.
 
@@ -806,11 +804,7 @@ have v0.23 C<Catalyst::Model::DBIC::Schema> as discussed above):
     $
     $ # Then re-run the helper to build the files for "load_namespaces"
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-    $
-    $ # Note that the '\' above is a line continuation marker and
-    $ # should NOT be included as part of the command
-
+        create=static dbi:SQLite:myapp.db
     $
     $ # Now convert the existing files over
     $ cd lib/MyApp/Schema
@@ -907,9 +901,9 @@ display something like:
     [debug] Statistics enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.23                                       |
-    | Catalyst::Plugin::StackTrace  0.10                                         |
-    | Catalyst::Plugin::Static::Simple  0.21                                     |
+    | Catalyst::Plugin::ConfigLoader  0.27                                       |
+    | Catalyst::Plugin::StackTrace  0.11                                         |
+    | Catalyst::Plugin::Static::Simple  0.25                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -950,7 +944,7 @@ display something like:
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
     
-    [info] MyApp powered by Catalyst 5.80003
+    [info] MyApp powered by Catalyst 5.80013
     You can connect to your server at http://debian:3000
 
 B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
@@ -990,7 +984,7 @@ column will still be blank (we will fill that in later).
 Also notice in the output of the C<script/myapp_server.pl> that 
 DBIx::Class used the following SQL to retrieve the data:
 
-    SELECT me.id, me.title, me.rating FROM books me
+    SELECT me.id, me.title, me.rating FROM book me
 
 because we enabled DBIC_TRACE.
 
@@ -1011,10 +1005,10 @@ edit many individual files.
 =head2 Configure TT.pm For The Wrapper
 
 In order to create a wrapper, you must first edit your TT view and
-tell it where to find your wrapper file. Your TT view is located in
-C<lib/MyApp/View/TT.pm>.
+tell it where to find your wrapper file. 
 
-Edit C<lib/MyApp/View/TT.pm> and change it to match the following:
+Edit you TT view in C<lib/MyApp/View/TT.pm> and change it to match the 
+following:
 
     __PACKAGE__->config(
         # Change default TT extension
@@ -1190,7 +1184,7 @@ following text below the C<# You can replace this text...> comment:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     2) Name of the model class referenced by this relationship
     #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'book_id');
+    __PACKAGE__->has_many(book_authors => 'MyApp::Schema::Result::BookAuthor', 'book_id');
     
     # many_to_many():
     #   args:
@@ -1198,7 +1192,7 @@ following text below the C<# You can replace this text...> comment:
     #     2) Name of has_many() relationship this many_to_many() is shortcut for
     #     3) Name of belongs_to() relationship in model class of has_many() above
     #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(author => 'book_author', 'author');
+    __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
 
 
 B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
@@ -1214,10 +1208,10 @@ C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we
 will see examples on how to use DBIx::Class objects in your code soon, 
 but note that because C<$book-E<gt>book_author> can return multiple 
 authors, we have to use C<first> to display a single author). 
-C<many_to_many> allows us to use the shorter C<$book-E<gt>author-
-E<gt>first-E<gt>last_name>. Note that you cannot define a 
-C<many_to_many> relationship without also having the C<has_many> 
-relationship in place.
+C<many_to_many> allows us to use the shorter 
+C<$book-E<gt>author-E<gt>first-E<gt>last_name>. Note that you cannot 
+define a C<many_to_many> relationship without also having the 
+C<has_many> relationship in place.
 
 Then edit C<lib/MyApp/Schema/Result/Author.pm> and add relationship
 information as follows (again, be careful to put in above the C<1;> but
@@ -1232,7 +1226,7 @@ below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
     #     1) Name of relationship, DBIC will create an accessor with this name
     #     2) Name of the model class referenced by this relationship
     #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'author_id');
+    __PACKAGE__->has_many(book_authors => 'MyApp::Schema::Result::BookAuthor', 'author_id');
     
     # many_to_many():
     #   args:
@@ -1240,7 +1234,7 @@ below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
     #     2) Name of has_many() relationship this many_to_many() is shortcut for
     #     3) Name of belongs_to() relationship in model class of has_many() above
     #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(book => 'book_author', 'book');
+    __PACKAGE__->many_to_many(books => 'book_authors', 'book');
 
 Finally, do the same for the "join table,"
 C<lib/MyApp/Schema/Result/BookAuthor.pm>:
@@ -1277,9 +1271,8 @@ three dynamically created model class (one for each of the
 Result Classes we created).
 
 Then hit the URL L<http://localhost:3000/books/list> with your browser 
-and be sure that the book list is displayed via the relationships 
-established above. You can leave the development server running for 
-the next step if you wish.
+and be sure that the book list still displays correctly. You can leave 
+the development server running for the next step if you wish.
 
 B<Note:> You will not see the authors yet because the view does not yet 
 use the new relations. Read on to the next section where we update the 
@@ -1295,13 +1288,14 @@ the "empty" table cell "<td></td>" with the following:
 
     ...
     <td>
+      [% # NOTE: See Chapter 4 for a better way to do this!                      -%]
       [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
       [% # loop in 'side effect notation' to load just the last names of the     -%]
-      [% # authors into the list. Note that the 'push' TT vmethod does not print -%]
+      [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
       [% # a value, so nothing will be printed here.  But, if you have something -%]
-      [% # in TT that does return a method and you don't want it printed, you    -%]
-      [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to     -%]
-      [% # call it and discard the return value.                                 -%]
+      [% # in TT that does return a value and you don't want it printed, you     -%]
+      [% # 1) assign it to a bogus value, or                                     -%]
+      [% # 2) use the CALL keyword to call it and discard the return value.      -%]
       [% tt_authors = [ ];
          tt_authors.push(author.last_name) FOREACH author = book.authors %]
       [% # Now use a TT 'virtual method' to display the author count in parens   -%]
@@ -1312,6 +1306,15 @@ the "empty" table cell "<td></td>" with the following:
     </td>
     ...
 
+B<IMPORTANT NOTE:> Again, you should keep as much "logic code" as 
+possible out of your views.  This kind of logic belongs in your model 
+(the same goes for controllers -- keep them as "thin" as possible and 
+push all of the "complicated code" out to your model objects).  Avoid 
+code like you see in the previous example -- we are only using it here 
+to show some extra features in TT until we get to the more advanced 
+model features we will see in Chapter 4 (see 
+L<Catalyst::Manual::Tutorial::04_BasicCRUD/EXPLORING THE POWER OF DBIC>).
+
 Then hit "Reload" in your browser (note that you don't need to reload 
 the development server or use the C<-r> option when updating TT 
 templates) and you should now see the number of authors each book has 
@@ -1325,17 +1328,17 @@ enabled, you should also now see five more C<SELECT> statements in the
 debug output (one for each book as the authors are being retrieved by
 DBIx::Class):
 
-    SELECT me.id, me.title, me.rating FROM books me:
+    SELECT me.id, me.title, me.rating FROM book me:
     SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '1'
+    JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
     SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '2'
+    JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
     SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '3'
+    JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
     SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '4'
+    JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
     SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '5'
+    JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
 
 Also note in C<root/src/books/list.tt2> that we are using "| html", a 
 type of TT filter, to escape characters such as E<lt> and E<gt> to &lt; 
@@ -1423,6 +1426,35 @@ detailed information on how to extend C<RenderView> in C<sub end>.
 =back
 
 
+=head2 RenderView's "dump_info" Feature
+
+One of the nice features of C<RenderView> is that it automatically 
+allows you to add C<dump_info=1> to the end of any URL for your 
+application and it will force the display of the "exception dump" 
+screen to the client browser.  You can try this out by starting the 
+development server as before and then point your browser to this URL: 
+
+    http://localhost:3000/books/list?dump_info=1
+
+You should get a page with the following message at the top:
+
+    Caught exception in MyApp::Controller::Root->end "Forced debug - 
+    Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
+
+Along with a summary of your application's state at the end of the 
+processing for that request.  The "Stash" section should show a 
+summarized version of the DBIC book model objects.  If desired, you 
+can adjust the summarization logic (called "scrubbing" logic) -- see 
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for 
+details.
+
+Note that you shouldn't need to worry about "normal clients" using 
+this technique to "reverse engineer" your application -- C<RenderView> 
+only supports the C<dump_info=1> feature when your application is 
+running in C<-Debug> mode (something you won't do once you have your 
+application deployed in production).
+
+
 =head2 Using The Default Template Name
 
 By default, C<Catalyst::View::TT> will look for a template that uses the
@@ -1470,6 +1502,7 @@ Chapter 9 of the Tutorial).
 B<IMPORTANT:> Make sure that you do NOT skip the following section
 before continuing to the next chapter 4 Basic CRUD.
 
+
 =head2 Return To A Manually Specified Template
 
 In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
@@ -1492,7 +1525,7 @@ Kennedy Clark, C<hkclark@gmail.com>
 
 Please report any errors, issues or suggestions to the author.  The
 most recent version of the Catalyst Tutorial can be found at
-L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
 
 Copyright 2006-2008, Kennedy Clark, under Creative Commons License
 (L<http://creativecommons.org/licenses/by-sa/3.0/us/>).