Merge from depluralization branch
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / MoreCatalystBasics.pod
index c2edcbe..7e54dcb 100644 (file)
@@ -190,11 +190,11 @@ Then replace it with:
 
     # Load plugins
     use Catalyst qw/-Debug
-                ConfigLoader
-                Static::Simple
+                    ConfigLoader
+                    Static::Simple
                 
-                StackTrace
-                /;
+                    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,6 +213,14 @@ 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
+the StackTrace plugin the Makefile.PL should include the following
+line:
+
+    requires 'Catalyst::Plugin::StackTrace';
+
+
 B<Notes:> 
 
 =over 4
@@ -273,7 +281,7 @@ 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::Books')->all];
+        # $c->stash->{books} = [$c->model('DB::Book')->all];
         # But, for now, use this code until we create the model later
         $c->stash->{books} = '';
     
@@ -344,7 +352,7 @@ 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 except.  See 
+how many arguments an action should accept.  See 
 L<Catalyst::Manual::Intro/Action_types> for more information and a few 
 examples.
 
@@ -499,6 +507,7 @@ Then create C<root/src/books/list.tt2> in your editor and enter:
       <tr>
         <td>[% book.title %]</td>
         <td>[% book.rating %]</td>
+        <td></td>
       </tr>
     [% END -%]
     </table>
@@ -558,18 +567,18 @@ C<myapp01.sql> in your editor and enter:
     --
     -- Create a very simple database to hold book and author information
     --
-    CREATE TABLE books (
+    CREATE TABLE book (
             id          INTEGER PRIMARY KEY,
             title       TEXT ,
             rating      INTEGER
     );
-    -- 'book_authors' is a many-to-many join table between books & authors
-    CREATE TABLE book_authors (
+    -- 'book_author' is a many-to-many join table between books & authors
+    CREATE TABLE book_author (
             book_id     INTEGER,
             author_id   INTEGER,
             PRIMARY KEY (book_id, author_id)
     );
-    CREATE TABLE authors (
+    CREATE TABLE author (
             id          INTEGER PRIMARY KEY,
             first_name  TEXT,
             last_name   TEXT
@@ -577,27 +586,27 @@ C<myapp01.sql> in your editor and enter:
     ---
     --- Load some sample data
     ---
-    INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
-    INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
-    INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
-    INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
-    INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
-    INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
-    INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
-    INSERT INTO authors VALUES (3, 'Christian', 'Degu');
-    INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
-    INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
-    INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
-    INSERT INTO authors VALUES (7, 'Nathan', 'Torkington');
-    INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
-    INSERT INTO book_authors VALUES (1, 1);
-    INSERT INTO book_authors VALUES (1, 2);
-    INSERT INTO book_authors VALUES (1, 3);
-    INSERT INTO book_authors VALUES (2, 4);
-    INSERT INTO book_authors VALUES (3, 5);
-    INSERT INTO book_authors VALUES (4, 6);
-    INSERT INTO book_authors VALUES (4, 7);
-    INSERT INTO book_authors VALUES (5, 8);
+    INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
+    INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
+    INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
+    INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
+    INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
+    INSERT INTO author VALUES (1, 'Greg', 'Bastien');
+    INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
+    INSERT INTO author VALUES (3, 'Christian', 'Degu');
+    INSERT INTO author VALUES (4, 'Richard', 'Stevens');
+    INSERT INTO author VALUES (5, 'Douglas', 'Comer');
+    INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
+    INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
+    INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
+    INSERT INTO book_author VALUES (1, 1);
+    INSERT INTO book_author VALUES (1, 2);
+    INSERT INTO book_author VALUES (1, 3);
+    INSERT INTO book_author VALUES (2, 4);
+    INSERT INTO book_author VALUES (3, 5);
+    INSERT INTO book_author VALUES (4, 6);
+    INSERT INTO book_author VALUES (4, 7);
+    INSERT INTO book_author VALUES (5, 8);
 
 Then use the following command to build a C<myapp.db> SQLite database:
 
@@ -614,7 +623,7 @@ database contents:
     $ sqlite3 myapp.db
     SQLite version 3.5.9
     Enter ".help" for instructions
-    sqlite> select * from books;
+    sqlite> select * from book;
     1|CCSP SNRS Exam Certification Guide|5
     2|TCP/IP Illustrated, Volume 1|5
     3|Internetworking with TCP/IP Vol.1|4
@@ -625,7 +634,7 @@ database contents:
 
 Or:
 
-    $ sqlite3 myapp.db "select * from books"
+    $ sqlite3 myapp.db "select * from book"
     1|CCSP SNRS Exam Certification Guide|5
     2|TCP/IP Illustrated, Volume 1|5
     3|Internetworking with TCP/IP Vol.1|4
@@ -638,39 +647,82 @@ 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.
+
 For using other databases, such as PostgreSQL or MySQL, see 
 L<Appendix 2|Catalyst::Manual::Tutorial::Appendices>.
 
 
 =head1 DATABASE ACCESS WITH DBIx::Class
 
-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>
-interface. However, most Catalyst applications use some form of
-object-relational mapping (ORM) technology to create objects associated
-with tables in a relational database.  Although L<Class::DBI|Class::DBI>
-has been a popular choice in the past, Matt Trout's
-L<DBIx::Class|DBIx::Class> (abbreviated as "DBIC") has rapidly emerged
-as the Perl-based ORM technology of choice. Most new Catalyst
-applications rely on DBIC, as will this tutorial.
+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> 
+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 
+associated with tables in a relational database.  Matt Trout's 
+L<DBIx::Class|DBIx::Class> (abbreviated as "DBIC") has rapidly emerged 
+as the Perl-based ORM technology of choice. Most new Catalyst 
+applications rely on DBIx::Class, as will this tutorial.
+
+Although DBIx::Class has included support for a C<create=dynamic> mode 
+to automatically read the database structure every time the 
+application starts, it's use is no longer recommended.  While it can 
+make for "flashy" demos, the use of the C<create=static> mode we use 
+below can be implemented just as quickly and provides many advantages 
+(such as the ability to add your own methods to the overall DBIC 
+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:
+
+    $ perl -MCatalyst::Model::DBIC::Schema -e \
+        'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
+    0.23
 
+(please note that the '\' above is a line continuation marker and
+should NOT be included as part of the command)
 
-=head2 Create a Dynamic DBIC Model
+If you don't have version 0.23 or higher, please run this command
+to install it directly from CPAN:
+
+    $ sudo cpan Catalyst::Model::DBIC::Schema
 
-Use the C<create=dynamic> model helper option to build a model that
-dynamically reads your database structure every time the application
-starts:
+And re-run the version print command to verify that you are now at 
+0.23 or higher.
+
+
+=head2 Create Static DBIx::Class Schema Files
+
+Before you continue, make sure your C<myapp.db> database file is in 
+the application's topmost directory. Now use the model helper with 
+the C<create=static> option to read the database with 
+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=dynamic dbi:SQLite:myapp.db
+        create=static components=TimeStamp dbi:SQLite:myapp.db
      exists "/home/me/MyApp/script/../lib/MyApp/Model"
      exists "/home/me/MyApp/script/../t"
-     exists "/home/me/MyApp/script/../lib/MyApp"
-    created "/home/me/MyApp/script/../lib/MyApp/Schema.pm"
+    Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
+    Schema dump completed.
     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)
 
 The C<script/myapp_create.pl> command breaks down like this:
 
@@ -692,10 +744,15 @@ C<lib/MyApp/Schema.pm>.
 
 =item *
 
-Because we specified C<create=dynamic> to the helper, it use 
+C<create=static> causes 
 L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> to 
-dynamically load the schema information from the database every time 
-the application starts.
+load the schema as it runs and then write that information out
+into files.
+
+=item *
+
+C<components=TimeStamp> causes the help to include the 
+L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp> DBIC component.
 
 =item *
 
@@ -704,17 +761,79 @@ for use with SQLite.
 
 =back
 
-B<NOTE:> Although the C<create=dynamic> option to the DBIC helper
-makes for a nifty demonstration, is only really suitable for very
-small applications. After this demonstration, you should almost always
-use the C<create=static> option that we will switch to below.
+If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
+only contains a call to the C<load_namespaces> method.  You will also 
+find that C<lib/MyApp> contains a C<Schema> subdirectory, which then 
+has a subdirectory called "Result".  This "Result" subdirectory then 
+has files named according to each of the tables in our simple database 
+(C<Author.pm>, C<BookAuthor.pm>, and C<Book.pm>).  These three 
+files are called "Result Classes" in DBIx::Class nomenclature. Although the 
+Result Class files are named after tables in our database, the classes 
+correspond to the I<row-level data> that is returned by DBIC (more on 
+this later, especially in 
+L<Catalyst::Manual::Tutorial::BasicCRUD/EXPLORING THE POWER OF DBIC>).
+
+The idea with the Result Source files created under 
+C<lib/MyApp/Schema/Result> by the C<create=static> option is to only 
+edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> 
+warning. If you place all of your changes below that point in the 
+file, you can regenerate the automatically created information at the 
+top of each file should your database structure get updated.
+
+Also note the "flow" of the model information across the various files 
+and directories.  Catalyst will initially load the model from 
+C<lib/MyApp/Model/DB.pm>.  This file contains a reference to 
+C<lib/MyApp/Schema.pm>, so that file is loaded next.  Finally, the 
+call to C<load_namespaces> in C<Schema.pm> will load each of the 
+"Result Class" files from the C<lib/MyApp/Schema/Result> subdirectory. 
+The final outcome is that Catalyst will dynamically create three 
+table-specific Catalyst models every time the application starts (you 
+can see these three model files listed in the debug output generated 
+when you launch the application).
+
+B<NOTE:> Older versions of 
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> use the 
+deprecated DBIx::Class C<load_classes> technique instead of the newer 
+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):
+
+    $ # 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"
+    $ 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).
 
 
 =head1 ENABLE THE MODEL IN THE CONTROLLER
 
 Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we 
 left disabled earlier so that your version matches the following (un-
-comment the line containing C<[$c-E<gt>model('DB::Books')-E<gt>all]> 
+comment the line containing C<[$c-E<gt>model('DB::Book')-E<gt>all]> 
 and delete the next 2 lines):
 
     =head2 list
@@ -731,7 +850,7 @@ and delete the next 2 lines):
     
         # 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::Books')->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 (action methods respond to user input in
@@ -739,8 +858,8 @@ and delete the next 2 lines):
         $c->stash->{template} = 'books/list.tt2';
     }
 
-B<TIP>: You may see the C<$c-E<gt>model('DB::Books')> un-commented 
-above written as C<$c-E<gt>model('DB')-E<gt>resultset('Books')>.  The 
+B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented 
+above written as C<$c-E<gt>model('DB')-E<gt>resultset('Book')>.  The 
 two are equivalent.  Either way, C<$c-E<gt>model> returns a 
 L<DBIx::Class::ResultSet|DBIx::Class::ResultSet> which handles queries 
 against the database and iterating over the set of results that is 
@@ -751,7 +870,7 @@ supports a wide variety of more advanced operations to easily do
 things like filtering and sorting the results.  For example, the 
 following could be used to sort the results by descending title:
 
-    $c->model('DB::Books')->search({}, {order_by => 'title DESC'});
+    $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
 
 Some other examples are provided in 
 L<DBIx::Class::Manual::Cookbook/Complex WHERE clauses>, with 
@@ -788,9 +907,9 @@ display something like:
     [debug] Statistics enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.20                                       |
-    | Catalyst::Plugin::StackTrace  0.08                                         |
-    | Catalyst::Plugin::Static::Simple  0.20                                     |
+    | Catalyst::Plugin::ConfigLoader  0.23                                       |
+    | Catalyst::Plugin::StackTrace  0.10                                         |
+    | Catalyst::Plugin::Static::Simple  0.21                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -804,9 +923,9 @@ display something like:
     | MyApp::Controller::Books                                        | instance |
     | MyApp::Controller::Root                                         | instance |
     | MyApp::Model::DB                                                | instance |
-    | MyApp::Model::DB::Authors                                       | class    |
-    | MyApp::Model::DB::BookAuthors                                   | class    |
-    | MyApp::Model::DB::Books                                         | class    |
+    | MyApp::Model::DB::Author                                        | class    |
+    | MyApp::Model::DB::Book                                          | class    |
+    | MyApp::Model::DB::BookAuthor                                    | class    |
     | MyApp::View::TT                                                 | instance |
     '-----------------------------------------------------------------+----------'
     
@@ -831,7 +950,7 @@ display something like:
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
     
-    [info] MyApp powered by Catalyst 5.71000
+    [info] MyApp powered by Catalyst 5.80003
     You can connect to your server at http://debian:3000
 
 B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
@@ -849,8 +968,8 @@ Some things you should note in the output above:
 
 Catalyst::Model::DBIC::Schema dynamically created three model classes,
 one to represent each of the three tables in our database
-(C<MyApp::Model::DB::Authors>, C<MyApp::Model::DB::BookAuthors>,
-and C<MyApp::Model::DB::Books>).
+(C<MyApp::Model::DB::Author>, C<MyApp::Model::DB::BookAuthor>,
+and C<MyApp::Model::DB::Book>).
 
 =item *
 
@@ -868,8 +987,8 @@ books loaded by the C<myapp01.sql> script above without any formatting.
 The rating for each book should appear on each row, but the "Author(s)"
 column will still be blank (we will fill that in later).
 
-Also notice in the output of the C<script/myapp_server.pl> that DBIC
-used the following SQL to retrieve the data:
+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
 
@@ -1053,132 +1172,13 @@ provide a template that fills in the C<content> section of our wrapper
 template -- the wrapper will provide the overall feel of the page.
 
 
-=head1 A STATIC DATABASE MODEL WITH DBIx::Class
-
-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:
-
-    $ perl -MCatalyst::Model::DBIC::Schema -e \
-        'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.23
-
-If you don't have version 0.23 or higher, please 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.
-
-
-=head2 Create Static DBIC Schema Files
-
-Unlike the previous DBIC section where we had C<create=dynamic>
-automatically discover the structure of the database every time the
-application started, here we will use static schema files for more
-control.  This is typical of most "real world" applications.
-
-One option would be to manually create a separate schema file for each 
-table in the database. However, let's use the same 
-L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> we used 
-earlier with C<create=dynamic> to build the static files for us. 
-First, let's remove the schema file created earlier:
-
-    $ rm lib/MyApp/Schema.pm
-
-Now regenerate the schema using the C<create=static> option:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp 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 ...
-    Schema dump completed.
-     exists "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
-
-We could have also deleted C<lib/MyApp/Model/DB.pm>, but it would
-have regenerated the same file (note the C<exists> in the output above).
-If you take a look at C<lib/MyApp/Model/DB.pm>, it simply contains
-a reference to the actual schema file in C<lib/MyApp/Schema.pm>
-along with the database connect string.
-
-If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
-is no longer using 
-L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> as its base 
-class (L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> is 
-only being used by the helper to load the schema once and then create 
-the static files for us) and C<Schema.pm> only contains a call to the 
-C<load_namespaces> method.  You will also find that C<lib/MyApp> 
-contains a C<Schema> subdirectory, which then has a subdirectory 
-called "Result".  This "Result" subdirectory then has files named 
-according to each of the tables in our simple database (C<Authors.pm>, 
-C<BookAuthors.pm>, and C<Books.pm>).  These three files are called 
-"Result Classes" in DBIC nomenclature. Although the Result Class files 
-are named after tables in our database, the classes correspond to the 
-I<row-level data> that is returned by DBIC (more on this later, 
-especially in 
-L<Catalyst::Manual::Tutorial::BasicCRUD/EXPLORING THE POWER OF DBIC>).
-
-The idea with the Result Source files created under 
-C<lib/MyApp/Schema/Result> by the C<create=static> option is to only 
-edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> 
-warning. If you place all of your changes below that point in the 
-file, you can regenerate the automatically created information at the 
-top of each file should your database structure get updated.
-
-Also note the "flow" of the model information across the various files 
-and directories.  Catalyst will initially load the model from 
-C<lib/MyApp/Model/DB.pm>.  This file contains a reference to 
-C<lib/MyApp/Schema.pm>, so that file is loaded next.  Finally, the 
-call to C<load_namespaces> in C<Schema.pm> will load each of the 
-"Result Class" files from the C<lib/MyApp/Schema/Result> subdirectory. 
-The final outcome is that Catalyst will dynamically create three 
-table-specific Catalyst models every time the application starts (you 
-can see these three model files listed in the debug output generated 
-when you launch the application).
-
-B<NOTE:> Older versions of 
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> use the 
-deprecated DBIC C<load_classes> technique instead of the newer 
-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):
-
-    $ # 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"
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-    $
-    $ # 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).
-
-
-=head2 Updating the Generated DBIC Result Class Files
+=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/Books.pm> and add the 
+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:
 
     #
@@ -1190,7 +1190,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_authors => 'MyApp::Schema::Result::BookAuthors', 'book_id');
+    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'book_id');
     
     # many_to_many():
     #   args:
@@ -1198,7 +1198,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(authors => 'book_authors', 'author');
+    __PACKAGE__->many_to_many(author => 'book_author', 'author');
 
 
 B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
@@ -1206,31 +1206,20 @@ 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.
 
-C<Important Note:> Although this tutorial uses plural names for both 
-the names of the SQL tables and therefore the Result Classes (after 
-all, C<Schema::Loader> automatically named the Result Classes from the 
-names of the SQL tables it found), DBIC users prefer singular names 
-for these items.  B<Please try to use singular table and DBIC 
-model/Result Class names in your applications.>  This tutorial will 
-migrate to singular names as soon as possible (patches welcomed). 
-B<Note that while singular is preferred for the DBIC model, plural is 
-perfectly acceptable for the names of the controller classes.>  After 
-all, the C<Books.pm> controller operates on multiple books.
-
-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 it, we would have to
-"walk" though the C<book_authors> table as in 
-C<$book-E<gt>book_authors-E<gt>first-E<gt>author-E<gt>last_name> 
-(we will see examples on how to use DBIC objects in your code soon, 
-but note that because C<$book-E<gt>book_authors> can return multiple 
+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 
+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>authors-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/Authors.pm> and add relationship
+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):
 
@@ -1243,7 +1232,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::BookAuthors', 'author_id');
+    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'author_id');
     
     # many_to_many():
     #   args:
@@ -1251,10 +1240,10 @@ 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(books => 'book_author', 'book');
+    __PACKAGE__->many_to_many(book => 'book_author', 'book');
 
 Finally, do the same for the "join table,"
-C<lib/MyApp/Schema/Result/BookAuthors.pm>:
+C<lib/MyApp/Schema/Result/BookAuthor.pm>:
 
     #
     # Set relationships:
@@ -1265,14 +1254,14 @@ C<lib/MyApp/Schema/Result/BookAuthors.pm>:
     #     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::Books', 'book_id');
+    __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::Authors', 'author_id');
+    __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
 
 
 =head2 Run The Application
@@ -1301,11 +1290,8 @@ template to do that.
 
 Let's add a new column to our book list page that takes advantage of 
 the relationship information we manually added to our schema files in 
-the previous section.  Edit C<root/src/books/list.tt2> and add the 
-following code below the existing table cell that contains 
-C<book.rating> (IOW, add a new table cell below the existing two 
-C<E<lt>tdE<gt>> tags but above the closing C<E<lt>/trE<gt>> and 
-C<E<lt>/tableE<gt>> tags):
+the previous section.  Edit C<root/src/books/list.tt2> and replace
+the "empty" table cell "<td></td>" with the following:
 
     ...
     <td>
@@ -1337,19 +1323,19 @@ browser window.)
 If you are still running the development server with C<DBIC_TRACE>
 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
-DBIC):
+DBIx::Class):
 
     SELECT me.id, me.title, me.rating FROM books me:
-    SELECT author.id, author.first_name, author.last_name FROM book_authors me  
-    JOIN authors author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '1'
-    SELECT author.id, author.first_name, author.last_name FROM book_authors me  
-    JOIN authors author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '2'
-    SELECT author.id, author.first_name, author.last_name FROM book_authors me  
-    JOIN authors author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '3'
-    SELECT author.id, author.first_name, author.last_name FROM book_authors me  
-    JOIN authors author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '4'
-    SELECT author.id, author.first_name, author.last_name FROM book_authors me  
-    JOIN authors author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '5'
+    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'
+    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'
+    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'
+    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'
+    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'
 
 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; 
@@ -1463,7 +1449,7 @@ 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::Books')->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
@@ -1481,6 +1467,8 @@ you will B<not> be able to use either the C<$c-E<gt>forward> or
 the C<$c-E<gt>detach> mechanisms (these are discussed in Chapter 2 and
 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