clarified docs on pural table naming
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 03_MoreCatalystBasics.pod
index 208b02c..1f66bac 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
@@ -182,19 +200,22 @@ For our application, we want to add one new plugin into the mix.  To
 do this, edit C<lib/MyApp.pm> (this file is generally referred to as 
 your I<application class>) and delete the lines with:
 
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple/;
+    use Catalyst qw/
+        -Debug
+        ConfigLoader
+        Static::Simple
+    /;
 
 Then replace it with:
 
     # Load plugins
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple
-                
-                    StackTrace
-                    /;
+    use Catalyst qw/
+        -Debug
+        ConfigLoader
+        Static::Simple
+    
+        StackTrace
+    /;
 
 B<Note:> Recent versions of C<Catalyst::Devel> have used a variety of 
 techniques to load these plugins/flags.  For example, you might see
@@ -213,8 +234,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
+dependency within the Makefile.PL file. For example, after adding
 the StackTrace plugin the Makefile.PL should include the following
 line:
 
@@ -239,10 +260,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 +334,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 +370,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 +425,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 +468,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 +518,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,15 +555,16 @@ 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.
 
 
 =head1 CREATE A SQLITE DATABASE
 
 In this step, we make a text file with the required SQL commands to
-create a database table and load some sample data.  We will use SQLite,
-a popular database that is lightweight and easy to use.  Open
+create a database table and load some sample data.  We will use 
+SQLite (L<http://www.sqlite.org>), a popular database that is
+lightweight and easy to use. Be sure to get at least version 3. Open
 C<myapp01.sql> in your editor and enter:
 
     --
@@ -574,8 +577,8 @@ C<myapp01.sql> in your editor and enter:
     );
     -- 'book_author' is a many-to-many join table between books & authors
     CREATE TABLE book_author (
-            book_id     INTEGER,
-            author_id   INTEGER,
+            book_id     INTEGER REFERENCES book(id) ON DELETE CASCADE ON UPDATE CASCADE,
+            author_id   INTEGER REFERENCES author(id) ON DELETE CASCADE ON UPDATE CASCADE,
             PRIMARY KEY (book_id, author_id)
     );
     CREATE TABLE author (
@@ -647,14 +650,14 @@ required if you do a single SQL statement on the command line).  Use
 ".q" to exit from SQLite from the SQLite interactive mode and return to
 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>
-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.
+Please note that here we have chosen to use 'singular' table names. This is
+because the default inflection code for older versions
+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. you think that they
+are easier to read) then see the documentation in
+L<DBIx::Class::Schema::Loader::Base/naming> (version 0.05 or greater).
 
 For using other databases, such as PostgreSQL or MySQL, see 
 L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices>.
@@ -664,7 +667,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,19 +693,23 @@ 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.
 
+Please use version C<1.27> of L<DBD::SQLite> or later for proper foreign key
+support.
 
 =head2 Create Static DBIx::Class Schema Files
 
@@ -713,7 +720,8 @@ 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 \
+        on_connect_do="PRAGMA foreign_keys = ON"
      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 +729,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 +760,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.
 
@@ -798,36 +802,15 @@ C<load_namspaces>.  For new applications, please try to use
 C<load_namespaces> since it more easily supports a very useful DBIC 
 technique called "ResultSet Classes."  If you need to convert an 
 existing application from "load_classes" to "load_namespaces," you can 
-use this process to automate the migration (but first make sure you 
-have v0.23 C<Catalyst::Model::DBIC::Schema> as discussed above):
+use this process to automate the migration, but first make sure you have
+version C<0.39> of L<Catalyst::Model::DBIC::Schema> and
+L<DBIx::Class::Schema::Loader> version C<0.05000> or later.
 
-    $ # First delete the existing schema file to disable "compatibility" mode
-    $ rm lib/MyApp/Schema.pm
-    $
-    $ # Then re-run the helper to build the files for "load_namespaces"
+    $ # Re-run the helper to upgrade for you
     $ 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
-
-    $
-    $ # Now convert the existing files over
-    $ cd lib/MyApp/Schema
-    $ perl -MIO::All -e 'for (@ARGV) { my $s < io($_); $s =~ s/.*\n\# You can replace.*?\n//s;
-          $s =~ s/'MyApp::Schema::/'MyApp::Schema::Result::/g; my $d < io("Result/$_");
-          $d =~ s/1;\n?//; "$d$s" > io("Result/$_"); }' *.pm
-    $ cd ../../..
-    $
-    $ # And finally delete the old files
-    $ rm lib/MyApp/Schema/*.pm
-
-The "C<perl -MIO::ALL ...>" script will copy all the customized 
-relationship (and other) information below "C<# DO NOT MODIFY>" line 
-from the old files in C<lib/MyApp/Schema> to the new files in 
-C<lib/MyApp/Schema/Result> (we will be starting to add some 
-"customized relationship information in the section below).
-
+        create=static naming=current use_namespaces=1 \
+        dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
 
 =head1 ENABLE THE MODEL IN THE CONTROLLER
 
@@ -907,9 +890,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 +933,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 +973,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 +994,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
@@ -1175,94 +1158,48 @@ template -- the wrapper will provide the overall feel of the page.
 =head2 Updating the Generated DBIx::Class Result Class Files
 
 Let's manually add some relationship information to the auto-generated 
-Result Class files. (Note: if you are using a database other than 
-SQLite, such as PostgreSQL, then the relationship could have been 
-automatically placed in the Result Class files.  If so, you can skip 
-this step.)  First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
+Result Class files. C<many_to_many> relationships are not currently
+automatically generated by L<DBIx::Class::Schema::Loader>.
+First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
 following text below the C<# You can replace this text...> comment:
 
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     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');
-    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     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
 file.  As with any Perl package, we need to end the last line with
 a statement that evaluates to C<true>.  This is customarily done with
 C<1;> on a line by itself.
 
-This code defines both a C<has_many> and a C<many_to_many> 
-relationship. The C<many_to_many> relationship is optional, but it 
-makes it easier to map a book to its collection of authors.  Without 
+You'll notice there is already a C<has_many> relationship called
+C<book_authors>. The C<many_to_many> relationship is optional, but it makes it
+easier to map a book to its collection of authors.  Without 
 it, we would have to "walk" though the C<book_author> table as in 
 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
 below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
 
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     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');
-    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     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');
-
-Finally, do the same for the "join table,"
-C<lib/MyApp/Schema/Result/BookAuthor.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # belongs_to():
-    #   args:
-    #     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 *this* table
-    __PACKAGE__->belongs_to(book => 'MyApp::Schema::Result::Book', 'book_id');
-    
-    # belongs_to():
-    #   args:
-    #     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 *this* table
-    __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
-
+    __PACKAGE__->many_to_many(books => 'book_authors', 'book');
 
 =head2 Run The Application
 
@@ -1277,9 +1214,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 +1231,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 +1249,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 +1271,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 +1369,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 +1445,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 +1468,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/>).