Update flow to assume using 0.39+ C::M::DBIC::Schema now that debian pkg available.
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 03_MoreCatalystBasics.pod
index 208b02c..a8e1f31 100644 (file)
@@ -91,21 +91,25 @@ 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
 
-One of the greatest benefits of Catalyst is that it has such a large
-library of plugins and base classes available.  Plugins are used to
-seamlessly integrate existing Perl modules into the overall Catalyst
-framework.  In general, they do this by adding additional methods to the
-C<context> object (generally written as C<$c>) that Catalyst passes to
-every component throughout the framework.
+One of the greatest benefits of Catalyst is that it has such a large 
+library of bases classes and plugins available that you can use easily 
+add functionality to your application. Plugins are used to seamlessly 
+integrate existing Perl modules into the overall Catalyst framework. In 
+general, they do this by adding additional methods to the C<context> 
+object (generally written as C<$c>) that Catalyst passes to every 
+component throughout the framework. 
+
 
 By default, Catalyst enables three plugins/flags:
 
@@ -119,15 +123,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 +202,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
@@ -205,7 +228,7 @@ the following:
 Don't let these variations confuse you -- they all accomplish the same 
 result.
 
-This tells Catalyst to start using one new plugin, 
+This tells Catalyst to start using one additional plugin, 
 L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>, to add a 
 stack trace to the standard Catalyst "debug screen" (the screen 
 Catalyst sends to your browser when an error occurs). Be aware that 
@@ -213,8 +236,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 +262,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
 
@@ -273,7 +295,7 @@ and add the following method to the controller:
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
@@ -281,14 +303,14 @@ and add the following method to the controller:
     
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
-        # $c->stash->{books} = [$c->model('DB::Book')->all];
+        # $c->stash(books => [$c->model('DB::Book')->all]);
         # But, for now, use this code until we create the model later
-        $c->stash->{books} = '';
+        $c->stash(books => '');
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 B<TIP>: See Appendix 1 for tips on removing the leading spaces when
@@ -303,7 +325,7 @@ is used to pass information between components and provide access to
 Catalyst and plugin functionality.
 
 Catalyst actions are regular Perl methods, but they make use of 
-attributes (the "C<: Local>" next to the "C<sub list>" in the code 
+attributes (the "C<:Local>" next to the "C<sub list>" in the code 
 above) to provide additional information to the Catalyst dispatcher 
 logic (note that the space between the colon and the attribute name is 
 optional; you will see attributes written both ways).  Most Catalyst 
@@ -314,7 +336,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 +372,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 +427,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 +470,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,28 +520,32 @@ 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
 
 To test your work so far, first start the development server:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 Then point your browser to L<http://localhost:3000> and you should
 still get the Catalyst welcome page.  Next, change the URL in your
@@ -553,20 +557,22 @@ 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:
 
     --
     -- Create a very simple database to hold book and author information
     --
+    PRAGMA foreign_keys = ON;
     CREATE TABLE book (
             id          INTEGER PRIMARY KEY,
             title       TEXT ,
@@ -574,8 +580,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 (
@@ -621,8 +627,9 @@ can use the SQLite command line environment to do a quick dump of the
 database contents:
 
     $ sqlite3 myapp.db
-    SQLite version 3.5.9
+    SQLite version 3.6.22
     Enter ".help" for instructions
+    Enter SQL statements terminated with a ";"
     sqlite> select * from book;
     1|CCSP SNRS Exam Certification Guide|5
     2|TCP/IP Illustrated, Volume 1|5
@@ -647,14 +654,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 of
+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 +671,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 
@@ -685,23 +692,36 @@ framework, a technique that we see in Chapter 4).
 =head2 Make Sure You Have a Recent Version of the DBIx::Class Model
 
 First, let's be sure we have a recent version of the DBIC helper,
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, by
-running this command:
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, so
+that we can take advantage of some recent enhancements in how
+foreign keys are handled with SQLite.  To check your version, 
+run this command:
 
     $ perl -MCatalyst::Model::DBIC::Schema -e \
         'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.23
+    0.4
 
-(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:
+If you are following along in Debian 5, you should have version 0.40 or 
+higher (shown above as "0.4" with the tailing zero removed). If you have 
+less than v0.39, you will 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.39 or higher.
+
+In addition, since we are using SQLite's foreign key support here,
+please be sure that you use version C<1.27> of L<DBD::SQLite> or later:
+
+    $ perl -MDBD::SQLite -e 'print "$DBD::SQLite::VERSION\n"'
+    1.29
+
+Upgrade if you are not at version C<1.27> or higher.
 
 
 =head2 Create Static DBIx::Class Schema Files
@@ -713,7 +733,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 +742,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,13 +773,20 @@ into files.
 
 =item *
 
-C<components=TimeStamp> causes the help to include the 
-L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp> DBIC component.
+C<dbi:SQLite:myapp.db> is the standard DBI connect string 
+for use with SQLite.
 
 =item *
 
-And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
-for use with SQLite.
+And finally, the C<on_connect_do> string requests that 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> create 
+foreign key relationships for us (this is not needed for databases such 
+as PostgreSQL and MySQL, but is required for SQLite). If you take a look 
+at C<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is 
+propogated to the Model, so that SQLite's recent (and optional) foreign 
+key enforcement is enabled at the start of every database connection. 
+
+
 
 =back
 
@@ -798,35 +827,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
@@ -842,20 +851,20 @@ and delete the next 2 lines):
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
     
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
+        # Retrieve all of the book records as book model objects and store
+        # in the stash where they can be accessed by the TT template
+        $c->stash(books => [$c->model('DB::Book')->all]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented 
@@ -885,9 +894,11 @@ and L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>.
 First, let's enable an environment variable that causes DBIx::Class to 
 dump the SQL statements used to access the database.  This is a 
 helpful trick when you are trying to debug your database-oriented 
-code:
+code.  Press C<Ctrl-C> to break out of the development server and
+enter:
 
     $ export DBIC_TRACE=1
+    $ script/myapp_server.pl -r 
 
 This assumes you are using bash as your shell -- adjust accordingly if
 you are using a different shell (for example, under tcsh, use
@@ -902,14 +913,13 @@ log).
 Then launch the Catalyst development server.  The log output should
 display something like:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
     [debug] Debug messages enabled
     [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                                         |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -950,7 +960,7 @@ display something like:
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
     
-    [info] MyApp powered by Catalyst 5.80003
+    [info] MyApp powered by Catalyst 5.80020
     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 +1000,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 +1021,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
@@ -1163,123 +1173,180 @@ provide lots of high-quality CSS functionality.
 
 =head2 Test Run The Application
 
-Restart the development server and hit "Reload" in your web browser
-and you should now see a formatted version of our basic book list.
-Although our wrapper and stylesheet are obviously very simple, you
-should see how it allows us to control the overall look of an entire
-website from two central files.  To add new pages to the site, just
-provide a template that fills in the C<content> section of our wrapper
-template -- the wrapper will provide the overall feel of the page.
+Hit "Reload" in your web browser and you should now see a formatted 
+version of our basic book list. (Again, the development server should 
+have automatically restarted when you made changes to 
+C<lib/MyApp/View/TT.pm>. If you are not using the "-r" option, you will 
+need to hit C<Ctrl-C> and manually restart it. Also note that the 
+development server does I<NOT> need to restart for changes to the TT and 
+static files we created and edited in the C<root> directory -- those 
+updates are handled on a per-request basis.) 
+
+Although our wrapper and stylesheet are obviously very simple, you 
+should see how it allows us to control the overall look of an entire 
+website from two central files. To add new pages to the site, just 
+provide a template that fills in the C<content> section of our wrapper 
+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 
-following text below the C<# You can replace this text...> comment:
+If you take a look at the Schema files automatically generated by 
+L<DBIx::Class::Schema::Loader>, you will see that it has already defined 
+C<has_many> and C<belongs_to> relationships on each side of our foreign 
+keys. For example, take a look at C<lib/MyApp/Schema/Result/Book.pm> and 
+notice the following code: 
+
+    =head1 RELATIONS
+
+    =head2 book_authors
+
+    Type: has_many
+
+    Related object: L<MyApp::Schema::Result::BookAuthor>
+
+    =cut
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      { "foreign.book_id" => "self.id" },
+    );
+
+Each C<Book> "has_many" C<book_authors>, where C<BookAuthor> is
+the many-to-many table that allows each Book to have multiple
+Authors, and each Author to have mulitple books.  The arguments
+to C<has_many> are:
+
+=over 4
+
+=item *
+
+C<book_authors> - The name for this relationship.  DBIC will create
+an accessor on the C<Books> DBIC Row object with this name.
+
+=item *
+
+C<MyApp::Schema::Result::BookAuthor> - The name of the DBIC model
+class referenced by this C<has_many> relationship.
+
+=item *
+
+C<foreign.book_id> - C<book_id> is the name of the foreign key 
+column in the I<foreign> table that points back to this table.
+
+=item *
+
+C<self.id> - C<id> is the name of the column in I<this> table
+that is referenced by the foreign key.
+
+=back
+
+See L<DBIx::Class::Relationship/has_many> for
+additional information.  Note that you might see a "hand coded"
+version of the C<has_many> relationship above expressed as:
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      "book_id",
+    );
+
+Where the third argument is simply the name of the column in
+the foreign table.  However, the hashref syntax used by 
+L<DBIx::Class::Schema::Loader> is more flexible (for example,
+it can handle "multi-column" foreign keys).
+
+B<Note:> If you are using older versions of SQLite and related DBIC 
+tools, you will need to manually define your C<has_many> and 
+C<belongs_to> relationships. We recommend upgrading to the versions 
+specified above. :-) 
+
+Have a look at C<lib/MyApp/Schema/Result/BookAuthor.pm> and notice
+that there is a C<belongs_to> relationship defined that acts as the
+"mirror image" to the C<has_many> relationship we just looked at
+above:
+
+    =head1 RELATIONS
+
+    =head2 book
+
+    Type: belongs_to
+
+    Related object: L<MyApp::Schema::Result::Book>
+
+    =cut
+
+    __PACKAGE__->belongs_to(
+      "book",
+      "MyApp::Schema::Result::Book",
+      { id => "book_id" },
+      { join_type => "LEFT" },
+    );
+
+The arguments are similar, but see 
+L<DBIx::Class::Relationship/belongs_to> for the details.
+
+Although recent versions of SQLite and L<DBIx::Class::Schema::Loader> 
+automatically handle the C<has_many> and C<belongs_to> relationships, 
+C<many_to_many> relationships currently need to be manually inserted. 
+To add a C<many_to_many> relationship, 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 
+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.
-
-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');
-    
+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 the reverse 
+C<many_to_many> relationship for C<Author> as follows (again, be careful 
+to put in above the C<1;> but below the C<# DO NOT MODIFY THIS OR 
+ANYTHING ABOVE!> comment): 
+
     # 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
 
 Run the Catalyst development server script with the C<DBIC_TRACE> option
 (it might still be enabled from earlier in the tutorial, but here is an
-alternate way to specify the option just in case):
+alternate way to specify the trace option just in case):
 
-    $ DBIC_TRACE=1 script/myapp_server.pl
+    $ DBIC_TRACE=1 script/myapp_server.pl -r
 
 Make sure that the application loads correctly and that you see the
 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.
 
 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 +1362,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 +1380,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 +1402,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 +1500,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 pointing 
+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
@@ -1441,7 +1547,7 @@ has changed):
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
@@ -1449,18 +1555,17 @@ has changed):
     
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
+        $c->stash(books => [$c->model('DB::Book')->all]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (actions methods respond to user input in
         # your controllers).
-        #$c->stash->{template} = 'books/list.tt2';
+        #$c->stash(template => 'books/list.tt2');
     }
 
 
-You should now be able to restart the development server as per the
-previous section and access the L<http://localhost:3000/books/list>
-as before.
+You should now be able to access the L<http://localhost:3000/books/list>
+URL as before.
 
 B<NOTE:> Please note that if you use the default template technique,
 you will B<not> be able to use either the C<$c-E<gt>forward> or
@@ -1470,20 +1575,20 @@ 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>
 later in the tutorial, you should remove the comment from the
 statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
 
-    $c->stash->{template} = 'books/list.tt2';
+    $c->stash(template => 'books/list.tt2');
 
 Then delete the C<TEMPLATE_EXTENSION> line in
 C<lib/MyApp/View/TT.pm>.
 
-You should then be able to restart the development server and
-access L<http://localhost:3000/books/list> in the same manner as
-with earlier sections.
+Check the L<http://localhost:3000/books/list> URL in your browser.
+It should look the same manner as with earlier sections.
 
 
 =head1 AUTHOR
@@ -1492,7 +1597,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/>).