[Catalyst-commits] r7772 - in trunk/Catalyst-Manual/lib/Catalyst/Manual: . Tutorial

hkclark at dev.catalyst.perl.org hkclark at dev.catalyst.perl.org
Thu May 22 18:35:29 BST 2008


Author: hkclark
Date: 2008-05-22 18:35:28 +0100 (Thu, 22 May 2008)
New Revision: 7772

Added:
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
Modified:
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Appendices.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authentication.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authorization.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Debugging.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Intro.pod
   trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Testing.pod
Log:
Rework tutorial.  Lots of things changed, but key items include: new content in CatalystBasics from Gerda S, move most of old CatalystBasics to MoreCatalystBasics, fix Authentication and Authorization, add PostgreSQL code from Louis M, etc.

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Appendices.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Appendices.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Appendices.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Appendices - Catalyst Tutorial - Part 9: Appendices
+Catalyst::Manual::Tutorial::Appendices - Catalyst Tutorial - Part 10: Appendices
 
 
 =head1 OVERVIEW
 
-This is B<Part 9 of 9> of the Catalyst tutorial.
+This is B<Part 10 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,30 +21,34 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 B<Appendices>
 
 =back
@@ -400,10 +404,355 @@
 
 =head2 PostgreSQL
 
-B<TODO> -- Please see the latest version of this document for possible updates:
-L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/Appendices.pod>
+Use the following steps to adapt the tutorial to PostgreSQL.  Thanks to
+Louis Moore for the help who was in turn helped by Marcello Romani and 
+Tom Lanyon.
 
+=over 4
 
+=item *
+
+Part 2: Catalyst Basics
+
+=over 4
+
+=item *
+
+Install the required software:
+
+=over 4
+
+=item *
+
+The PostgreSQL database server and client.
+
+=item *
+
+The Perl C<DBD::Pg> module
+
+=back
+
+=item *
+
+Create the database and a user for the database
+
+    $ createuser -P catmyapp
+    Enter password for new role: <catalyst> 
+    Enter it again: <catalyst>
+    Shall the new role be a superuser? (y/n) n
+    Shall the new role be allowed to create databases? (y/n) n
+    Shall the new role be allowed to create more new roles? (y/n) n
+    CREATE ROLE
+    $ createdb -O catmyapp mycatapp
+    CREATE DATABASE
+
+=item *
+
+Create the C<.sql> file and load the data:
+
+=over 4
+
+=item *
+
+Open the C<myapp01_psql.sql> in your editor and enter:
+
+
+     --
+     -- Create a very simple database to hold book and author information
+     --
+     -- The sequence is how we get a unique id in PostgreSQL
+     --
+     CREATE SEQUENCE books_seq START 5 ;
+     SELECT nextval ('books_seq');
+
+     CREATE TABLE books (
+        id          INTEGER PRIMARY KEY DEFAULT nextval('books_seq'),
+        title       TEXT ,
+        rating      INTEGER
+        );
+
+     -- 'book_authors' is a many-to-many join table between books & authors
+     CREATE TABLE book_authors (
+        book_id     INTEGER,
+        author_id   INTEGER,
+        PRIMARY KEY (book_id, author_id)
+
+        );
+
+     CREATE SEQUENCE authors_seq START 8 ;
+     SELECT nextval ('authors_seq');
+
+     CREATE TABLE authors (
+     id          INTEGER PRIMARY KEY DEFAULT nextval('authors_seq'),
+     first_name  TEXT,
+     last_name   TEXT
+     );
+     ---
+     --- 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);
+
+=item *
+
+Load the data:
+
+    $ psql -U catmyapp -W mycatapp
+    Password for user catmyapp: catalyst 
+    Welcome to psql 8.1.8, the PostgreSQL interactive terminal.
+
+    Type:  \copyright for distribution terms
+           \h for help with SQL commands
+           \? for help with psql commands
+           \g or terminate with semicolon to execute query
+           \q to quit
+
+    mycatapp=> \i myapp01_psql.sql
+
+    CREATE SEQUENCE
+    nextval 
+    ---------
+           5
+    (1 row)
+
+    psql:myapp01_psql.sql:11: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "books_pkey" for table "books"
+    CREATE TABLE
+    psql:myapp01_psql.sql:19: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "book_authors_pkey" for table 
+    "book_authors"
+    CREATE TABLE
+    CREATE SEQUENCE
+     nextval 
+    ---------
+          8
+    (1 row)
+
+    psql:myapp01_psql.sql:30: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "authors_pkey" for table "authors"
+    CREATE TABLE
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    ...
+
+=item *
+
+Make sure the data loaded correctly:
+
+    mycatapp=> \dt
+                List of relations
+     Schema |     Name     | Type  |  Owner   
+    --------+--------------+-------+----------
+     public | authors      | table | catmyapp
+     public | book_authors | table | catmyapp
+     public | books        | table | catmyapp
+    (3 rows)
+
+    mycatapp=> select * from books;
+     id |               title                | rating 
+    ----+------------------------------------+--------
+      1 | CCSP SNRS Exam Certification Guide |      5
+      2 | TCP/IP Illustrated, Volume 1       |      5
+      3 | Internetworking with TCP/IP Vol.1  |      4
+      4 | Perl Cookbook                      |      5
+      5 | Designing with Web Standards       |      5
+     (5 rows)
+
+    mycatapp=> \q
+
+=back
+
+=item *
+
+After the steps where you:
+
+    edit lib/MyApp.pm 
+
+    create lib/MyAppDB.pm 
+
+    create lib/MyAppDB/Book.pm
+
+    create lib/MyAppDB/Author.pm
+
+    create lib/MyAppDB/BookAuthor.pm 
+
+
+=item *
+
+Generate the model using the Catalyst "_create.pl" script:
+
+    script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB 'dbi:Pg:dbname=mycatapp' 'catmyapp' 'catalyst' '{ AutoCommit => 1 }'
+
+
+=back
+
+=item *
+
+Part 4: Authentication
+
+=over 4
+
+=item *
+
+Create the C<.sql> file for the user/roles data:
+
+Open C<myapp02_psql.sql> in your editor and enter:
+
+    --
+    -- Add users and roles tables, along with a many-to-many join table
+    --
+
+    CREATE SEQUENCE users_seq START 3 ;
+    SELECT nextval ('users_seq');
+
+    CREATE TABLE users (
+            id            INTEGER PRIMARY KEY DEFAULT nextval('users_seq'),
+            username      TEXT,
+            password      TEXT,
+            email_address TEXT,
+            first_name    TEXT,
+            last_name     TEXT,
+            active        INTEGER
+    );
+
+    CREATE SEQUENCE roles_seq START 2 ;
+    SELECT nextval ('roles_seq');
+
+    CREATE TABLE roles (
+            id   INTEGER PRIMARY KEY DEFAULT nextval('roles_seq'),
+            role TEXT
+    );
+
+    CREATE TABLE user_roles (
+            user_id INTEGER,
+            role_id INTEGER,
+            PRIMARY KEY (user_id, role_id)
+    );
+
+    --
+    -- Load up some initial test data
+    --
+    INSERT INTO users VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
+    INSERT INTO users VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
+    INSERT INTO users VALUES (3, 'test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
+    INSERT INTO roles VALUES (1, 'user');
+    INSERT INTO roles VALUES (2, 'admin');
+    INSERT INTO user_roles VALUES (1, 1);
+    INSERT INTO user_roles VALUES (1, 2);
+    INSERT INTO user_roles VALUES (2, 1);
+    INSERT INTO user_roles VALUES (3, 1);
+
+=item *
+
+Load the data:
+
+    $ psql -U catmyapp -W mycatapp
+    Password for user catmyapp: catalyst 
+    Welcome to psql 8.1.8, the PostgreSQL interactive terminal.
+
+    Type:  \copyright for distribution terms
+           \h for help with SQL commands
+           \? for help with psql commands
+           \g or terminate with semicolon to execute query
+           \q to quit
+
+    mycatapp=> \i myapp02_psql.sql
+
+    CREATE SEQUENCE
+     nextval 
+    ---------
+           3
+    (1 row)
+
+    psql:myapp02_psql.sql:16: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
+    CREATE TABLE
+    CREATE SEQUENCE
+     nextval 
+    ---------
+           2
+    (1 row)
+
+    psql:myapp02_psql.sql:24: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "roles_pkey" for table "roles"
+    CREATE TABLE
+    psql:myapp02_psql.sql:30: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_roles_pkey" for table "user_roles"
+    CREATE TABLE
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    mycatapp=> 
+
+    mycatapp=> select * from users;
+     id | username | password | email_address | first_name | last_name | active 
+    ----+----------+----------+---------------+------------+-----------+--------
+      1 | test01   | mypass   | t01 at na.com    | Joe        | Blow      |      1
+      2 | test02   | mypass   | t02 at na.com    | Jane       | Doe       |      1
+      3 | test03   | mypass   | t03 at na.com    | No         | Go        |      0
+    (3 rows)
+
+
+=item *
+
+Create the C<.sql> file for the hashed password data:
+
+Open C<myapp03_psql.sql> in your editor and enter:
+
+    --
+    -- Convert passwords to SHA-1 hashes
+    --
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 1;
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 2;
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 3;
+
+=item *
+
+Load in the data
+
+    $ psql -U catmyapp -W mycatapp
+    Password for user catmyapp: 
+    Welcome to psql 8.1.8, the PostgreSQL interactive terminal.
+
+    Type:  \copyright for distribution terms
+           \h for help with SQL commands
+           \? for help with psql commands
+           \g or terminate with semicolon to execute query
+           \q to quit
+
+    mycatapp=> \i myapp03_psql.sql
+    UPDATE 1
+    UPDATE 1
+    UPDATE 1
+
+
+
+=back
+
+=back
+
+
 =head1 APPENDIX 3: IMPROVED HASHING SCRIPT
 
 Here is an improved SHA-1 hashing script from Gavin Henry that does

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authentication.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authentication.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authentication.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Authentication - Catalyst Tutorial - Part 4: Authentication
+Catalyst::Manual::Tutorial::Authentication - Catalyst Tutorial - Part 5: Authentication
 
 
 =head1 OVERVIEW
 
-This is B<Part 4 of 9> for the Catalyst tutorial.
+This is B<Part 5 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,49 +21,43 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-B<Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+B<Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
 
 
-=head1 IMPORTANT NOTE
-
-Since this tutorial was written, there has been a new Authentication
-API released (Catalyst::Plugin::Authentication version 0.1 and later).
-Some of this tutorial does not work with this API, and requires
-minimal changes.  For an example application that uses the new API see
-L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/NewAuthApp/NewAuthApp-0.01.tar.gz>. It
-is recommended that you read this tutorial first, and then download
-the source code linked above to understand the differences.
-
 =head1 DESCRIPTION
 
-Now that we finally have a simple yet functional application, we can
-focus on providing authentication (with authorization coming next in
+Now that we finally have a simple yet functional application, we can 
+focus on providing authentication (with authorization coming next in 
 Part 5).
 
 This part of the tutorial is divided into two main sections: 1) basic,
@@ -127,58 +121,29 @@
 
 =head2 Add User and Role Information to DBIC Schema
 
-This step adds DBIC-based classes for the user-related database tables
-(the role information will not be used until Part 5):
+Although we could manually edit the DBIC schema information to include
+the new tables added in the previous step, let's use the C<create=static>
+option on the DBIC model helper to do most of the work for us:
 
-Edit C<lib/MyAppDB.pm> and update the contents to match (only the
-C<MyAppDB =E<gt> [qw/Book BookAuthor Author User UserRole Role/]> line
-has changed):
+    $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db
+    $ ls lib/MyApp/Schema/MyAppDB
+    Authors.pm  BookAuthors.pm  Books.pm  Roles.pm  UserRoles.pm  Users.pm
 
-    package MyAppDB;
-    
-    =head1 NAME 
-    
-    MyAppDB -- DBIC Schema Class
-    
-    =cut
-    
-    # Our schema needs to inherit from 'DBIx::Class::Schema'
-    use base qw/DBIx::Class::Schema/;
-    
-    # Need to load the DB Model classes here.
-    # You can use this syntax if you want:
-    #    __PACKAGE__->load_classes(qw/Book BookAuthor Author User UserRole Role/);
-    # Also, if you simply want to load all of the classes in a directory
-    # of the same name as your schema class (as we do here) you can use:
-    #    __PACKAGE__->load_classes(qw//);
-    # But the variation below is more flexible in that it can be used to 
-    # load from multiple namespaces.
-    __PACKAGE__->load_classes({
-        MyAppDB => [qw/Book BookAuthor Author User UserRole Role/]
-    });
-    
-    1;
+Notice how the helper has added three new table-specific result source 
+files to the C<lib/MyApp/Schema/MyApp> directory.  And, more 
+importantly, even if there were changes to the existing result source 
+files, those changes would have only been written above the C<# DO NOT 
+MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-editted 
+enhancements would have been preserved.
 
 
-=head2 Create New "Result Source Objects"
+Speaking of "hand-editted enhancements," we should now add 
+relationship information to the three new result source files.  Edit 
+each of these files and add the following information between the C<# 
+DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
 
-Create the following three files with the content shown below.
+C<lib/MyApp/Schema/MyAppDB/Users.pm>:
 
-C<lib/MyAppDB/User.pm>:
-
-    package MyAppDB::User;
-    
-    use base qw/DBIx::Class/;
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('users');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/id username password email_address first_name last_name/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key('id');
-    
     #
     # Set relationships:
     #
@@ -188,41 +153,19 @@
     #     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
-    __PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'user_id');
+    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::MyAppDB::UserRoles', 'user_id');
     
-    
-    =head1 NAME
-    
-    MyAppDB::User - A model object representing a person with access to the system.
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'users' table of your application
-    database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    Offline utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
+    # 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(roles => 'map_user_role', 'role');
 
 
-C<lib/MyAppDB/Role.pm>:
+C<lib/MyApp/Schema/MyAppDB/Roles.pm>:
 
-    package MyAppDB::Role;
-    
-    use base qw/DBIx::Class/;
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('roles');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/id role/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key('id');
-    
     #
     # Set relationships:
     #
@@ -232,42 +175,11 @@
     #     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
-    __PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'role_id');
-    
-    
-    =head1 NAME
-    
-    MyAppDB::Role - A model object representing a class of access permissions to 
-    the system.
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'roles' table of your 
-    application database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    "Offline" utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
+    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::MyAppDB::UserRoles', 'role_id');
 
 
-C<lib/MyAppDB/UserRole.pm>:
+C<lib/MyApp/Schema/MyAppDB/UserRoles.pm>:
 
-    package MyAppDB::UserRole;
-    
-    use base qw/DBIx::Class/;
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('user_roles');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/user_id role_id/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key(qw/user_id role_id/);
-    
     #
     # Set relationships:
     #
@@ -277,41 +189,33 @@
     #     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(user => 'MyAppDB::User', 'user_id');
+    __PACKAGE__->belongs_to(user => 'MyApp::Schema::MyAppDB::Users', 'user_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(role => 'MyAppDB::Role', 'role_id');
-    
-    
-    =head1 NAME
-    
-    MyAppDB::UserRole - A model object representing the JOIN between Users and Roles.
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'user_roles' table of your application
-    database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    You probably won't need to use this class directly -- it will be automatically
-    used by DBIC where joins are needed.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    Offline utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
+    __PACKAGE__->belongs_to(role => 'MyApp::Schema::MyAppDB::Roles', 'role_id');
 
-The code for these three result source classes is obviously very familiar to the C<Book>, C<Author>, and C<BookAuthor> classes created in Part 2.
 
+The code for these three sets of updates is obviously very similar to 
+the edits we made to the C<Books>, C<Authors>, and C<BookAuthors> 
+classes created in Part 3.
 
+Note that we do not need to make any change to the 
+C<lib/MyApp/Schema/MyAppDB.pm> schema file.  It simple tells DBIC to 
+load all of the result source files it finds in below the 
+C<lib/MyApp/Schema/MyAppDB> directory, so it will automatically pick 
+up our new table information.
+
+
 =head2 Sanity-Check Reload of Development Server
 
-We aren't ready to try out the authentication just yet; we only want to do a quick check to be sure our model loads correctly.  Press C<Ctrl-C> to kill the previous server instance (if it's still running) and restart it:
+We aren't ready to try out the authentication just yet; we only want 
+to do a quick check to be sure our model loads correctly.  Press 
+C<Ctrl-C> to kill the previous server instance (if it's still running) 
+and restart it:
 
     $ script/myapp_server.pl
 
@@ -325,21 +229,23 @@
     | MyApp::Controller::Root                                           | instance |
     | MyApp::Model::MyAppDB                                             | instance |
     | MyApp::Model::MyAppDB::Author                                     | class    |
-    | MyApp::Model::MyAppDB::Book                                       | class    |
-    | MyApp::Model::MyAppDB::BookAuthor                                 | class    |
-    | MyApp::Model::MyAppDB::Role                                       | class    |
-    | MyApp::Model::MyAppDB::User                                       | class    |
-    | MyApp::Model::MyAppDB::UserRole                                   | class    |
+    | MyApp::Model::MyAppDB::Books                                      | class    |
+    | MyApp::Model::MyAppDB::BookAuthors                                | class    |
+    | MyApp::Model::MyAppDB::Roles                                      | class    |
+    | MyApp::Model::MyAppDB::Users                                      | class    |
+    | MyApp::Model::MyAppDB::UserRoles                                  | class    |
     | MyApp::View::TT                                                   | instance |
     '-------------------------------------------------------------------+----------'
     ...
 
-Again, notice that your "result source" classes have been "re-loaded" by Catalyst under C<MyApp::Model>.
+Again, notice that your "result source" classes have been "re-loaded" 
+by Catalyst under C<MyApp::Model>.
 
 
 =head2 Include Authentication and Session Plugins
 
-Edit C<lib/MyApp.pm> and update it as follows (everything below C<StackTrace> is new):
+Edit C<lib/MyApp.pm> and update it as follows (everything below 
+C<StackTrace> is new):
 
     use Catalyst qw/
             -Debug
@@ -355,37 +261,37 @@
             Session::State::Cookie
             /;
 
-The C<Authentication> plugin supports
-Authentication while the C<Session> plugins are required to maintain
-state across multiple HTTP requests.  
+The C<Authentication> plugin supports Authentication while the 
+C<Session> plugins are required to maintain state across multiple HTTP 
+requests.  
 
-Note that the only required Authentication class is the main
-one. This is a change that occured in version 0.09999_01
-of the C<Authentication> plugin. You B<do not need> to specify a 
-particular Authentication::Store or Authentication::Credential plugin. 
-Instead, indicate the Store and Credential you want to use in your application
+Note that the only required Authentication class is the main one. This 
+is a change that occurred in version 0.09999_01 of the 
+C<Authentication> plugin. You B<do not need> to specify a particular 
+Authentication::Store or Authentication::Credential plugin. Instead, 
+indicate the Store and Credential you want to use in your application 
 configuration (see below).
 
-Note that there are several
-options for L<Session::Store|Catalyst::Plugin::Session::Store>
-(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
-is generally a good choice if you are on Unix; try
-L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you
-are on Win32) -- consult
-L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses
-for additional information and options (for example to use a
-database-backed session store).
+Note that there are several options for 
+L<Session::Store|Catalyst::Plugin::Session::Store> 
+(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap> 
+is generally a good choice if you are on Unix; try 
+L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you 
+are on Win32) -- consult 
+L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses 
+for additional information and options (for example to use a database-
+backed session store).
 
 
 =head2 Configure Authentication
 
-Although C<__PACKAGE__-E<gt>config(name =E<gt> 'value');> is still
-supported, newer Catalyst applications tend to place all configuration
-information in C<myapp.yml> and automatically load this information into
-C<MyApp-E<gt>config> using the 
-L<ConfigLoader|Catalyst::Plugin::ConfigLoader> plugin.  Here, we need
+Although C<__PACKAGE__-E<gt>config(name =E<gt> 'value');> is still 
+supported, newer Catalyst applications tend to place all configuration 
+information in C<myapp.yml> and automatically load this information 
+into C<MyApp-E<gt>config> using the 
+L<ConfigLoader|Catalyst::Plugin::ConfigLoader> plugin.  Here, we need 
 to load several parameters that tell 
-L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
+L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> 
 where to locate information in your database.  To do this, edit the 
 C<myapp.yml> YAML and update it to match:
 
@@ -396,29 +302,39 @@
         realms:
             dbic:
                 credential:
-                    class: Password
+                    # Note this first definition would be the same as setting
+                    # __PACKAGE__->config->{authentication}->{realms}->{dbic}
+                    #     ->{credential} = 'Password' in lib/MyApp.pm 
+                    # (IOW, each hash key becomes a "name:" in the YAML file).
+                    #
+                    # Specify that we are going to do password-based auth
+                    class:          Password
+                    # This is the name of the field in the users table with the
+                    # password stored in it
                     password_field: password
-                    password_type:  self_check
+                    # We are using an unencrypted password now
+                    password_type:  clear
                 store:
+                    # Use DBIC to retrieve username, password & role information
                     class:          DBIx::Class
-            # This is the model object created by Catalyst::Model::DBIC from your
-            # schema (you created 'MyAppDB::User' but as the Catalyst startup
-            # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::User').
-            # NOTE: Omit 'MyApp::Model' to avoid a component lookup issue in Catalyst 5.66
-                    user_class:     MyApp::Users
-            # This is the name of the field in your 'users' table that contains the user's name
+                    # This is the model object created by Catalyst::Model::DBIC 
+                    # from your schema (you created 'MyAppDB::User' but as the 
+                    # Catalyst startup debug messages show, it was loaded as 
+                    # 'MyApp::Model::MyAppDB::Users').
+                    # NOTE: Omit 'MyApp::Model' here just as you would when using 
+                    # '$c->model("MyAppDB::Users)'
+                    user_class:     MyAppDB::Users
+                    # This is the name of the field in your 'users' table that 
+                    # contains the user's name
                     id_field:       username
-                    role_relation:  roles
-                    role_field:     rolename
-                    ignore_fields_in_find: [ 'remote_name' ]
 
 Inline comments in the code above explain how each field is being used.
 
-B<TIP>: Although YAML uses a very simple and easy-to-ready format, it
-does require the use of a consistent level of indenting.  Be sure you
-line up everything on a given 'level' with the same number of indents.
-Also, be sure not to use C<tab> characters (YAML does not support them
-because they are handled inconsistently across editors).
+B<TIP>: Although YAML uses a very simple and easy-to-ready format, it 
+does require the use of a consistent level of indenting.  Be sure you 
+line up everything on a given 'level' with the same number of indents. 
+Also, be sure B<not> to use C<tab> characters (YAML does not support 
+them because they are handled inconsistently across editors).
 
 
 =head2 Add Login and Logout Controllers
@@ -497,8 +413,8 @@
 modifier -- this forces the match on I<only> C</login>, not 
 C</login/somethingelse>.
 
-Next, update the corresponding method in C<lib/MyApp/Controller/Logout.pm>
-to match:
+Next, update the corresponding method in 
+C<lib/MyApp/Controller/Logout.pm> to match:
 
     =head2 index
     
@@ -593,22 +509,41 @@
         return 1;
     }
 
-B<Note:> Catalyst provides a number of different types of actions, such
-as C<Local>, C<Regex>, and C<Private>.  You should refer to
-L<Catalyst::Manual::Intro> for a more detailed explanation, but the
-following bullet points provide a quick introduction:
 
+B<Note:> Catalyst provides a number of different types of actions, 
+such as C<Local>, C<Regex>, C<Private> and the new C<Path>.  You 
+should refer to L<Catalyst::Manual::Intro|Catalyst::Manual::Intro> for 
+a more detailed explanation, but the following bullet points provide a 
+quick introduction:
+
 =over 4
 
 =item *
 
-The majority of application use C<Local> actions for items that respond
-to user requests and C<Private> actions for those that do not directly
-respond to user input.
+The majority of application have traditionally use C<Local> actions 
+for items that respond to user requests and C<Private> actions for 
+those that do not directly respond to user input.
 
 =item *
 
-There are five types of C<Private> actions: C<begin>, C<end>,
+Newer Catalyst applications tend to use C<Path> actions and the 
+C<Args> attribute because of their power and flexibility.  You can
+specify the path to match relative to the namespace of the current
+module as an argument to C<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>.
+
+=item *
+
+Automatic "chaining" of actions by the dispatcher is a powerful 
+feature that allows multiple methods to handle a single URL.  See 
+L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>
+for more information on chained actions.
+
+=item *
+
+There are five types of build-in C<Private> actions: C<begin>, C<end>,
 C<default>, C<index>, and C<auto>.
 
 =item *
@@ -658,7 +593,7 @@
        TT code, it's probably a little too subtle for use in "normal" 
        comments.
     %]
- </p>
+    </p>
 
 Although most of the code is comments, the middle few lines provide a
 "you are already logged in" reminder if the user returns to the login
@@ -695,7 +630,7 @@
 the Book List page.
 
 Open C<root/src/books/list.tt2> and add the following lines to the
-bottom:
+bottom (below the closing </table> tag):
 
     <p>
       <a href="[% Catalyst.uri_for('/login') %]">Login</a>
@@ -779,26 +714,37 @@
     ---
     name: MyApp
     authentication:
-        dbic:
-            # Note this first definition would be the same as setting
-            # __PACKAGE__->config->{authentication}->{dbic}->{user_class} = 'MyAppDB::User'
-            # in lib/MyApp.pm (IOW, each hash key becomes a "name:" in the YAML file).
-            #
-            # This is the model object created by Catalyst::Model::DBIC from your
-            # schema (you created 'MyAppDB::User' but as the Catalyst startup
-            # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::User').
-            # NOTE: Omit 'MyApp::Model' here just as you would when using 
-            # '$c->model("MyAppDB::User)'
-            user_class: MyAppDB::User
-            # This is the name of the field in your 'users' table that contains the user's name
-            user_field: username
-            # This is the name of the field in your 'users' table that contains the password
-            password_field: password
-            # Other options can go here for hashed passwords
-            # Enabled hashed passwords
-            password_type: hashed
-            # Use the SHA-1 hashing algorithm
-            password_hash_type: SHA-1
+        default_realm: dbic
+        realms:
+            dbic:
+                credential:
+                    # Note this first definition would be the same as setting
+                    # __PACKAGE__->config->{authentication}->{realms}->{dbic}
+                    #     ->{credential} = 'Password' in lib/MyApp.pm 
+                    # (IOW, each hash key becomes a "name:" in the YAML file).
+                    #
+                    # Specify that we are going to do password-based auth
+                    class:          Password
+                    # This is the name of the field in the users table with the
+                    # password stored in it
+                    password_field: password
+                    # Switch to more secure hashed passwords
+                    password_type:  hashed
+                    # Use the SHA-1 hashing algorithm
+                    password_hash_type: SHA-1
+                store:
+                    # Use DBIC to retrieve username, password & role information
+                    class:          DBIx::Class
+                    # This is the model object created by Catalyst::Model::DBIC 
+                    # from your schema (you created 'MyAppDB::User' but as the 
+                    # Catalyst startup debug messages show, it was loaded as 
+                    # 'MyApp::Model::MyAppDB::Users').
+                    # NOTE: Omit 'MyApp::Model' here just as you would when using 
+                    # '$c->model("MyAppDB::Users)'
+                    user_class:     MyAppDB::Users
+                    # This is the name of the field in your 'users' table that 
+                    # contains the user's name
+                    id_field:       username
 
 
 =head2 Try Out the Hashed Passwords
@@ -812,16 +758,7 @@
 login as before.  When done, click the "Logout" link on the login page
 (or point your browser at L<http://localhost:3000/logout>).
 
-B<Note:> If you receive the debug screen in your browser with a 
-C<Can't call method "stash" on an undefined value...> error message,
-make sure that you are using v0.07 of 
-L<Catalyst::Plugin::Authorization::ACL|Catalyst::Plugin::Authorization::ACL>.
-The following command can be a useful way to quickly dump the version number
-of this module on your system:
 
-    perl -MCatalyst::Plugin::Authorization::ACL -e 'print $Catalyst::Plugin::Authorization::ACL::VERSION, "\n";'
-
-
 =head1 USING THE SESSION FOR FLASH
 
 As discussed in Part 3 of the tutorial, C<flash> allows you to set
@@ -835,7 +772,8 @@
 tutorial.
 
 First, open C<lib/MyApp/Controller/Books.pm> and modify C<sub delete>
-to match the following:
+to match the following (everything after the model search line of code
+has changed):
 
     =head2 delete 
     
@@ -848,12 +786,12 @@
         my ($self, $c, $id) = @_;
     
         # Search for the book and then delete it
-        $c->model('MyAppDB::Book')->search({id => $id})->delete_all;
+        $c->model('MyAppDB::Books')->search({id => $id})->delete_all;
     
         # Use 'flash' to save information across requests until it's read
         $c->flash->{status_msg} = "Book deleted";
             
-        # Redirect the user back to the list page with status msg as an arg
+        # Redirect the user back to the list page
         $c->response->redirect($c->uri_for('/books/list'));
     }
 
@@ -874,10 +812,10 @@
 =head2 Try Out Flash
 
 Restart the development server and point your browser to 
-L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
-book.  Click the "Return to list" link and delete the "Test" book you
-just added.  The C<flash> mechanism should retain our "Book deleted" 
-status message across the redirect.
+L<http://localhost:3000/books/url_create/Test/1/4> to create an extra 
+several books.  Click the "Return to list" link and delete one of the 
+"Test" books you just added.  The C<flash> mechanism should retain our 
+"Book deleted" status message across the redirect.
 
 B<NOTE:> While C<flash> will save information across multiple requests,
 I<it does get cleared the first time it is read>.  In general, this is
@@ -887,7 +825,44 @@
 L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
 information.
 
+=head2 Switch To Flash-To-Stash
 
+Although the a use of flash above is certainly an improvement over the 
+C<status_msg> we employed in Part 4 of the tutorial, the C<status_msg 
+|| Catalyst.flash.status_msg> statement is a little ugly. A nice 
+alternative is to use the C<flash_to_stash> feature that automatically 
+copies the content of flash to stash.  This makes your code controller 
+and template code work regardless of where it was directly access, a 
+forward, or a redirect. To enable C<flash_to_stash>, you can either 
+set the value in C<lib/MyApp.pm> by changing the default 
+C<__PACKAGE__-E<gt>config> setting to something like:
+
+    __PACKAGE__->config(
+            name => 'MyApp',
+            session => {flash_to_stash => 1}
+        );
+
+B<or> add the following to C<myapp.yml>:
+
+    session:
+        flash_to_stash: 1
+
+The C<__PACKAGE__-E<gt>config> option is probably preferable here 
+since it's not something you will want to change at runtime without it 
+possibly breaking some of your code.
+
+Then edit C<root/lib/site/layout> and change the C<status_msg> line
+to look like the following:
+
+    <span class="message">[% status_msg %]</span>
+
+Restart the development server and go to
+L<http://localhost:3000/books/list> in your browser.  Delete another 
+of the "Test" books you added in the previous step.  Flash should still
+maintain the status message across the redirect even though you are no
+longer explicitly accessing C<Catalyst.flash>.
+
+
 =head1 AUTHOR
 
 Kennedy Clark, C<hkclark at gmail.com>

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authorization.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authorization.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Authorization.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 5: Authorization
+Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 6: Authorization
 
 
 =head1 OVERVIEW
 
-This is B<Part 5 of 9> for the Catalyst tutorial.
+This is B<Part 6 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,36 +21,39 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-B<Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+B<Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
 
 
-
 =head1 DESCRIPTION
 
 This part of the tutorial adds role-based authorization to the existing
@@ -79,8 +82,6 @@
             StackTrace
             
             Authentication
-            Authentication::Store::DBIC
-            Authentication::Credential::Password
             Authorization::Roles
             
             Session
@@ -91,47 +92,47 @@
 
 =head2 Add Config Information for Authorization
 
-Edit C<myapp.yml> and update it to match (everything from the
-"authorization:" line down is new):
+Edit C<myapp.yml> and update it to match the following (the 
+C<role_relation> and C<role_field> definitions are new):
 
     ---
     name: MyApp
     authentication:
-        dbic:
-            # Note this first definition would be the same as setting
-            # __PACKAGE__->config->{authentication}->{dbic}->{user_class} = 'MyAppDB::User'
-            # in lib/MyApp.pm (IOW, each hash key becomes a "name:" in the YAML file).
-            #
-            # This is the model object created by Catalyst::Model::DBIC from your
-            # schema (you created 'MyAppDB::User' but as the Catalyst startup
-            # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::User').
-            # NOTE: Omit 'MyApp::Model' here just as you would when using 
-            # '$c->model("MyAppDB::User)'
-            user_class: MyAppDB::User
-            # This is the name of the field in your 'users' table that contains the user's name
-            user_field: username
-            # This is the name of the field in your 'users' table that contains the password
-            password_field: password
-            # Other options can go here for hashed passwords
-            # Enabled hashed passwords
-            password_type: hashed
-            # Use the SHA-1 hashing algorithm
-            password_hash_type: SHA-1
-    authorization:
-        dbic:
-            # This is the model object created by Catalyst::Model::DBIC from your
-            # schema (you created 'MyAppDB::Role' but as the Catalyst startup
-            # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::Role').
-            # NOTE: Omit 'MyApp::Model' here just as you would when using 
-            # '$c->model("MyAppDB::User)'
-            role_class: MyAppDB::Role
-            # The name of the field in the 'roles' table that contains the role name
-            role_field: role
-            # The name of the accessor used to map a role to the users who have this role
-            # See the has_many() in MyAppDB/Role.pm
-            role_rel: map_user_role
-            # The name of the field in the user_role table that references the user
-            user_role_user_field: user_id
+        default_realm: dbic
+        realms:
+            dbic:
+                credential:
+                    # Note this first definition would be the same as setting
+                    # __PACKAGE__->config->{authentication}->{realms}->{dbic}
+                    #     ->{credential} = 'Password' in lib/MyApp.pm 
+                    # (IOW, each hash key becomes a "name:" in the YAML file).
+                    #
+                    # Specify that we are going to do password-based auth
+                    class:          Password
+                    # This is the name of the field in the users table with the
+                    # password stored in it
+                    password_field: password
+                    # We are using an unencrypted password now
+                    password_type:  clear
+                store:
+                    # Use DBIC to retrieve username, password & role information
+                    class:          DBIx::Class
+                    # This is the model object created by Catalyst::Model::DBIC 
+                    # from your schema (you created 'MyAppDB::User' but as the 
+                    # Catalyst startup debug messages show, it was loaded as 
+                    # 'MyApp::Model::MyAppDB::Users').
+                    # NOTE: Omit 'MyApp::Model' here just as you would when using 
+                    # '$c->model("MyAppDB::Users)'
+                    user_class:     MyAppDB::Users
+                    # This is the name of the field in your 'users' table that 
+                    # contains the user's name
+                    id_field:       username
+                    # This is the name of a many_to_many relation in the users
+                    # object that points to the roles for that user
+                    role_relation:  roles
+                    # This is the name of field in the roles table that contains
+                    # the role information
+                    role_field:     role
 
 
 =head2 Add Role-Specific Logic to the "Book List" Template
@@ -193,7 +194,7 @@
         if ($c->check_user_roles('admin')) {
             # Call create() on the book model object. Pass the table 
             # columns/field values we want to set as hash values
-            my $book = $c->model('MyAppDB::Book')->create({
+            my $book = $c->model('MyAppDB::Books')->create({
                     title   => $title,
                     rating  => $rating
                 });

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::BasicCRUD - Catalyst Tutorial - Part 3: Basic CRUD
+Catalyst::Manual::Tutorial::BasicCRUD - Catalyst Tutorial - Part 4: Basic CRUD
 
 
 =head1 OVERVIEW
 
-This is B<Part 3 of 9> for the Catalyst tutorial.
+This is B<Part 4 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,57 +21,61 @@
 
 =item 3
 
-B<Basic CRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+B<Basic CRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
 
 
-
 =head1 DESCRIPTION
 
 This part of the tutorial builds on the fairly primitive application
-created in Part 2 to add basic support for Create, Read, Update, and
+created in Part 3 to add basic support for Create, Read, Update, and
 Delete (CRUD) of C<Book> objects.  Note that the 'list' function in Part
 2 already implements the Read portion of CRUD (although Read normally
 refers to reading a single object; you could implement full read
 functionality using the techniques introduced below).  This section will
 focus on the Create and Delete aspects of CRUD.  More advanced
 capabilities, including full Update functionality, will be addressed in
-Part 8.
+Part 9.
 
 You can checkout the source code for this example from the catalyst
 subversion repository as per the instructions in
 L<Catalyst::Manual::Tutorial::Intro>
 
+
 =head1 FORMLESS SUBMISSION
 
-Our initial attempt at object creation will utilize the "URL arguments"
-feature of Catalyst (we will employ the more common form-based
-submission in the sections that follow).
+Our initial attempt at object creation will utilize the "URL 
+arguments" feature of Catalyst (we will employ the more common form-
+based submission in the sections that follow).
 
 
 =head2 Include a Create Action in the Books Controller
@@ -93,7 +97,7 @@
     
         # Call create() on the book model object. Pass the table 
         # columns/field values we want to set as hash values
-        my $book = $c->model('MyAppDB::Book')->create({
+        my $book = $c->model('MyAppDB::Books')->create({
                 title  => $title,
                 rating => $rating
             });
@@ -172,7 +176,7 @@
 plugins, that is, not Catalyst plugins) to add extra functionality to
 the base TT capabilities.  Here, the plugin allows L<Data::Dumper>
 "pretty printing" of objects and variables.  Other than that, the rest
-of the code should be familiar from the examples in Part 2.
+of the code should be familiar from the examples in Part 3.
 
 B<IMPORTANT NOTE> As mentioned earlier, the C<MyApp::View::TT.pm> view
 class created by TTSite redefines the name used to access the Catalyst
@@ -202,7 +206,7 @@
 Your browser should display " Added book 'TCPIP_Illustrated_Vol-2' by
 'Stevens' with a rating of 5." along with a dump of the new book model
 object.  You should also see the following DBIC debug messages displayed
-in the development server log messages:
+in the development server log messages if you have DBIC_TRACE set:
 
     INSERT INTO books (rating, title) VALUES (?, ?): `5', `TCPIP_Illustrated_Vol-2'
     INSERT INTO book_authors (author_id, book_id) VALUES (?, ?): `4', `6'
@@ -294,7 +298,7 @@
         my $author_id = $c->request->params->{author_id} || '1';
     
         # Create the book
-        my $book = $c->model('MyAppDB::Book')->create({
+        my $book = $c->model('MyAppDB::Books')->create({
                 title   => $title,
                 rating  => $rating,
             });
@@ -328,7 +332,7 @@
 
 B<Note:> Having the user enter the primary key ID for the author is
 obviously crude; we will address this concern with a drop-down list in
-Part 8.
+Part 9.
 
 
 =head1 A SIMPLE DELETE FEATURE
@@ -402,7 +406,7 @@
         my ($self, $c, $id) = @_;
     
         # Search for the book and then delete it
-        $c->model('MyAppDB::Book')->search({id => $id})->delete_all;
+        $c->model('MyAppDB::Books')->search({id => $id})->delete_all;
     
         # Set a status message to be displayed at the top of the view
         $c->stash->{status_msg} = "Book deleted.";
@@ -456,7 +460,7 @@
 We can improve the logic by converting to a redirect.  Unlike
 C<$c-E<gt>forward('list'))> or C<$c-E<gt>detach('list'))> that perform
 a server-side alteration in the flow of processing, a redirect is a
-client-side mechanism that causes the brower to issue an entirely
+client-side mechanism that causes the browser to issue an entirely
 new request.  As a result, the URL in the browser is updated to match
 the destination of the redirection URL.
 
@@ -475,7 +479,7 @@
         my ($self, $c, $id) = @_;
     
         # Search for the book and then delete it
-        $c->model('MyAppDB::Book')->search({id => $id})->delete_all;
+        $c->model('MyAppDB::Books')->search({id => $id})->delete_all;
     
         # Set a status message to be displayed at the top of the view
         $c->stash->{status_msg} = "Book deleted.";
@@ -488,18 +492,20 @@
 =head2 Try the Delete and Redirect Logic
 
 Restart the development server and point your browser to 
-L<http://localhost:3000/books/list>.  Delete the first copy of 
-"TCPIP_Illustrated_Vol-2", but notice that I<no green "Book deleted" 
-status message is displayed>.  Because the stash is reset on every
-request (and a redirect involves a second request), the 
-C<status_msg> is cleared before it can be displayed.
+L<http://localhost:3000/books/list> and delete the first copy of 
+"TCPIP_Illustrated_Vol-2".  The URL in your browser should return to 
+the L<http://localhost:3000/books/list> URL, so that is an 
+improvement, but notice that I<no green "Book deleted" status message 
+is displayed>.  Because the stash is reset on every request (and a 
+redirect involves a second request), the C<status_msg> is cleared 
+before it can be displayed.
 
 
 =head2 Using C<uri_for> to Pass Query Parameters
 
 There are several ways to pass information across a redirect. 
 In general, the best option is to use the C<flash> technique that we
-will see in Part 4 of the tutorial; however, here we will pass the
+will see in Part 5 of the tutorial; however, here we will pass the
 information via query parameters on the redirect itself.  Open 
 C<lib/MyApp/Controller/Books.pm> and update the existing 
 C<sub delete> method to match the following:
@@ -515,7 +521,7 @@
         my ($self, $c, $id) = @_;
     
         # Search for the book and then delete it
-        $c->model('MyAppDB::Book')->search({id => $id})->delete_all;
+        $c->model('MyAppDB::Books')->search({id => $id})->delete_all;
     
         # Redirect the user back to the list page with status msg as an arg
         $c->response->redirect($c->uri_for('/books/list', 

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -5,7 +5,7 @@
 
 =head1 OVERVIEW
 
-This is B<Part 2 of 9> for the Catalyst tutorial.
+This is B<Part 2 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,30 +21,34 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
@@ -52,9 +56,8 @@
 
 =head1 DESCRIPTION
 
-In this part of the tutorial, we will create a very basic Catalyst web
-application.  Though simple in many respects, this section will already
-demonstrate a number of powerful capabilities such as:
+In this part of the tutorial, we will create a very basic Catalyst web 
+application, demonstrating a number of powerful capabilities, such as:
 
 =over 4
 
@@ -107,1146 +110,306 @@
 subversion repository as per the instructions in
 L<Catalyst::Manual::Tutorial::Intro>
 
+
 =head1 CREATE A CATALYST PROJECT
 
-Catalyst provides a number of helper scripts that can be used to quickly
-flesh out the basic structure of your application. All Catalyst projects
-begin with the C<catalyst.pl> helper (see L<Catalyst::Helper|Catalyst::Helper>
-for more information on helpers).  Also note that as of Catalyst 5.7000,
-you will not have the helper scripts unless you install both 
-L<Catalyst::Runtime|Catalyst::Runtime> and L<Catalyst::Devel|Catalyst::Devel>.
+Catalyst provides a number of helper scripts that can be used to 
+quickly flesh out the basic structure of your application. All 
+Catalyst projects begin with the C<catalyst.pl> helper (see 
+L<Catalyst::Helper|Catalyst::Helper> for more information on helpers). 
+Also note that as of Catalyst 5.7000, you will not have the helper 
+scripts unless you install both L<Catalyst::Runtime|Catalyst::Runtime> 
+and L<Catalyst::Devel|Catalyst::Devel>.
 
-In the case of this tutorial, use the Catalyst C<catalyst.pl> script to
-initialize the framework for an application called C<MyApp>:
+In this first part of the tutorial, use the Catalyst 
+C<catalyst.pl> script to initialize the framework for an 
+application called C<Hello>:
 
-    $ catalyst.pl MyApp
-    created "MyApp"
-    created "MyApp/script"
-    created "MyApp/lib"
-    created "MyApp/root"
+    $ catalyst.pl Hello
+    created "Hello"
+    created "Hello/script"
+    created "Hello/lib"
+    created "Hello/root"
     ...
-    created "MyApp/script/myapp_create.pl"
-    $ cd MyApp
+    created "Hello/script/hello_create.pl"
+    $ cd Hello
 
 The C<catalyst.pl> helper script will display the names of the
-directories and files it creates.
+directories and files it creates:
 
-Though it's too early for any significant celebration, we already have a
-functioning application. Run the following command to run this
-application with the built-in development web server:
+    Changes               # Record of application changes
+    lib                   # Lib directory for Perl modules
+        Hello             # Application code directory
+            Controller    # Directory for Controller modules 
+            Model         # Directory for Models
+            View          # Directory for Views
+        Hello.pm          # Base application module
+    Makefile.PL           # Makefile to build application
+    hello.yml             # Application configuration file
+    README                # README file
+    root                  # Equiv of htdocs, dir for templates, css, javascript
+        favicon.ico
+        static            # Directory for static files
+            images        # Directory for image files used in welcome screen
+    script                # Directory for Perl scripts
+        hello_cgi.pl      # To run your app as a cgi (not recommended)
+        hello_create.pl   # To create models, views, controllers
+        hello_fastcgi.pl  # To run app as a fastcgi program
+        hello_server.pl   # The normal development server
+        hello_test.pl     # Test your app from the command line
+    t                     # Directory for tests
+        01app.t           # Test scaffold       
+        02pod.t           
+        03podcoverage.t 
 
-    $ script/myapp_server.pl
+
+Catalyst will "auto-discover" modules in the Controller, Model, and 
+View directories. When you use the hello_create.pl script it will 
+create Perl module scaffolds in those directories, plus test files in 
+the "t" directory. The default location for templates is in the "root" 
+directory. The scripts in the script directory will always start with 
+the lowercased version of your application name. If your app is 
+MaiTai, then the create script would be "maitai_create.pl".
+
+Though it's too early for any significant celebration, we already have 
+a functioning application. We can use the Catalyst supplied script to 
+start up a development server and view the default Catalyst page in 
+your browser. All scripts in the script directory should be run from 
+the base directory of your application, so change to the Hello 
+directory.
+
+Run the following command to start up the built-in development web 
+server:
+
+    $ script/hello_server.pl
     [debug] Debug messages enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.13                                       |
-    | Catalyst::Plugin::Static::Simple  0.14                                     |
+    | Catalyst::Plugin::ConfigLoader  0.17                                       |
+    | Catalyst::Plugin::Static::Simple  0.20                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
     [debug] Loaded engine "Catalyst::Engine::HTTP"
-    [debug] Found home "/home/me/MyApp"
-    [debug] Loaded Config "/home/me/myapp.yml"
+    [debug] Found home "/home/me/Hello"
+    [debug] Loaded Config "/home/me/Hello/hello.yml"
     [debug] Loaded components:
     .-----------------------------------------------------------------+----------.
     | Class                                                           | Type     |
     +-----------------------------------------------------------------+----------+
-    | MyApp::Controller::Root                                         | instance |
+    | Hello::Controller::Root                                         | instance |
     '-----------------------------------------------------------------+----------'
     
     [debug] Loaded Private actions:
     .----------------------+--------------------------------------+--------------.
     | Private              | Class                                | Method       |
     +----------------------+--------------------------------------+--------------+
-    | /default             | MyApp::Controller::Root              | default      |
-    | /end                 | MyApp::Controller::Root              | end          |
+    | /default             | Hello::Controller::Root              | default      |
+    | /end                 | Hello::Controller::Root              | end          |
     '----------------------+--------------------------------------+--------------'
     
-    [info] MyApp powered by Catalyst 5.7002
+    [info] Hello powered by Catalyst 5.7011
     You can connect to your server at http://localhost:3000
 
-B<NOTE>: Be sure you run the C<script/myapp_server.pl> command from the
-'base' directory of your application, not inside the C<script> directory 
-itself.  It doesn't make a difference at this point, but it will as soon
-as we get the database going in the next section.
-
-Point your web browser to L<http://localhost:3000> (substituting a 
+Point your web browser to 
+L<http://localhost:3000|http://localhost:3000> (substituting a 
 different hostname or IP address as appropriate) and you should be 
 greeted by the Catalyst welcome screen.  Information similar to the 
 following should be appended to the logging output of the development 
 server:
 
-    [info] *** Request 1 (0.043/s) [6003] [Fri Jul  7 13:32:53 2006] ***
+    [info] *** Request 1 (1.000/s) [10301] [Sun May 18 10:11:36 2008] ***
     [debug] "GET" request for "/" from "127.0.0.1"
-    [info] Request took 0.067675s (14.777/s)
+    [info] Request took 0.017964s (55.667/s)
     .----------------------------------------------------------------+-----------.
     | Action                                                         | Time      |
     +----------------------------------------------------------------+-----------+
-    | /default                                                       | 0.002844s |
-    | /end                                                           | 0.000207s |
+    | /default                                                       | 0.000540s |
+    | /end                                                           | 0.001246s |
     '----------------------------------------------------------------+-----------'
 
 Press Ctrl-C to break out of the development server.
 
 
-=head1 CREATE A SQLITE DATABASE
+=head1 HELLO WORLD
 
-In this step, we make a text file with the required SQL commands to
-create a database table and load some sample data.  Open C<myapp01.sql>
-in your editor and enter:
+=head2 The Simplest Way
 
-    --
-    -- Create a very simple database to hold book and author information
-    --
-    CREATE TABLE books (
-            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_id     INTEGER,
-            author_id   INTEGER,
-            PRIMARY KEY (book_id, author_id)
-    );
-    CREATE TABLE authors (
-            id          INTEGER PRIMARY KEY,
-            first_name  TEXT,
-            last_name   TEXT
-    );
-    ---
-    --- 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);
+The Root.pm controller is a place to put global actions that usually 
+execute on the root URL. Open the C<lib/Hello/Controller/Root.pm> file in 
+your editor. You will see the "default" subroutine, which is 
+responsible for displaying the welcome screen that you just saw in 
+your browser. Later on you'll want to change that to something more 
+reasonable, such as a "404" message but for now just leave it alone.
 
-B<TIP>: See Appendix 1 for tips on removing the leading spaces when
-cutting and pasting example code from POD-based documents.
+    sub default : Path : Args {
+        my ( $self, $c ) = @_;
 
-Then use the following command to build a C<myapp.db> SQLite database:
+        $c->response->body( $c->welcome_message );
+    }
 
-    $ sqlite3 myapp.db < myapp01.sql
+The "C<$c>" here refers to the Catalyst context, which is used to 
+access the Catalyst application. In addition to many other things, 
+the Catalyst context provides access to "response" and "request" 
+objects. (See L<Catalyst>, L<Catalyst::Response>, and L<Catalyst::Request>) 
 
-If you need to create the database more than once, you probably want to
-issue the C<rm myapp.db> command to delete the database before you use
-the C<sqlite3 myapp.db < myapp01.sql> command.
+C<$c->response->body> sets the HTTP response (see 
+L<Catalyst::Response>), while C<$c->welcome_message> is a special method 
+that returns the welcome message that you saw in your browser.
 
-Once the C<myapp.db> database file has been created and initialized, you
-can use the SQLite command line environment to do a quick dump of the
-database contents:
+The ": Path : Args" after the method name are attributes which determine 
+which URLs will be dispatched to this method. (Depending on your version of 
+Catalyst, it used to say "Private" but using that with default is 
+currently deprecated.)
 
-    $ sqlite3 myapp.db
-    SQLite version 3.2.2
-    Enter ".help" for instructions
-    sqlite> select * from books;
-    1|CCSP SNRS Exam Certification Guide|5
-    2|TCP/IP Illustrated, Volume 1|5
-    3|Internetworking with TCP/IP Vol.1|4
-    4|Perl Cookbook|5
-    5|Designing with Web Standards|5
-    sqlite> .q
-    $
+Some MVC frameworks handle dispatching in a central place. Catalyst, 
+by policy, prefers to handle URL dispatching with attributes on 
+controller methods. There is a lot of flexibility in specifying which 
+URLs to match.  This particular method will match all URLs, because it 
+doesn't specify the path (nothing comes after "Path"), and will accept 
+any number of args (nothing after args). 
 
-Or:
+The default is to map URLs to controller names, and because of 
+the way that Perl handles namespaces through package names, 
+it is simple to create hierarchical structures in 
+Catalyst. This means that you can create controllers with deeply 
+nested actions in a clean and logical way. 
 
-    $ sqlite3 myapp.db "select * from books"
-    1|CCSP SNRS Exam Certification Guide|5
-    2|TCP/IP Illustrated, Volume 1|5
-    3|Internetworking with TCP/IP Vol.1|4
-    4|Perl Cookbook|5
-    5|Designing with Web Standards|5
+For example, the URL C<http://hello.com/admin/articles/create> maps 
+to the package C<Hello::Controller::Admin::Articles>, and the C<create>
+method. 
 
-As with most other SQL tools, if you are using the full "interactive"
-environment you need to terminate your SQL commands with a ";" (it's not
-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.
 
+Add the following subroutine to your Root.pm file:
 
-=head1 EDIT THE LIST OF CATALYST PLUGINS
+    sub hello : Global {
+        my ( $self, $c ) = @_;
+        $c->response->body("Hello, World!");
+    }
 
-One of the greatest benefits of Catalyst is that it has such a large
-library of plugins 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.
+Here you're sending your own string to the webpage.
 
-By default, Catalyst enables three plugins/flags:
+Save the file, start the server (stop and restart it if it's still 
+up), and go to L<http://localhost:3000/hello|http://localhost:3000> to 
+see "Hello, World!"
 
-=over 4
+=head2 Hello, World! Using a View and a Template
 
-=item * 
+In the Catalyst world  a "View" is not a page of XHTML or a template 
+designed to present a page to a browser. It is the module that 
+determines the type of view--HTML, pdf, XML. For the case of a 
+template view (such as the default Toolkit Template) the actual 
+templates go under the "root" directory.
 
-C<-Debug> Flag
+To create a TT view, run:
 
-Enables the Catalyst debug output you saw when we started the
-C<script/myapp_server.pl> development server earlier.  You can remove
-this plugin when you place your application into production.
+    $ script/hello_create.pl view TT TT
 
-As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
-Although most of the items specified on the C<use Catalyst> 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>).
+This creates the C<lib/Hello/View/TT.pm> module, which is a subclass of 
+C<Catalyst::View::TT>. The "view" keyword tells the create script that 
+you are creating a view, the first "TT" tells it that you are creating 
+a Template Toolkit view, and the second "TT" tells the script to name 
+the View module "TT.pm", which is a commonly used name for TT views. 
+(You can name it anything you want, such as "HTML.pm".) If you look at 
+TT.pm, you will find that it only contains a config statement to set 
+the TT extension to ".tt".
 
-If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
-messages.
+Now that the TT.pm "View" exists, Catalyst will autodiscover it and be 
+able to use it to display the view templates, using the "process" 
+method that it inherits from the C<Catalyst::View::TT class>.
 
-=item *
+Template Toolkit is a rather complicated template facility, with 
+excellent docs at 
+L<http://template-tookit.org/|http://template-tookit.org/>, 
+but since this is not a TT tutorial, we'll stick to only basic TT 
+usage here (and explore some of the more common TT features in later 
+parts of the tutorial).
 
-L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
+Create a C<root/hello.tt> template file (put it in the C<root> under 
+the C<Hello> directory that is the base of your application). Here is 
+a simple sample:
+  
+    [% META title = 'Hello, World!' %]
+    <p>
+        This is a TT view template, located in the root directory.
+    </p>
 
-C<ConfigLoader> provides an automatic way to load configurable
-parameters for your application from a central YAML file (versus having
-the values hard-coded inside your Perl modules).  If you have not been
-exposed to YAML before, it is a human-readable data serialization format
-that can be used to read (and write) values to/from text files.  We will
-see how to use this feature of Catalyst during the authentication and
-authorization sections (Part 4 and Part 5).
+[% and %] are markers for the TT parts of the template. Inside you can 
+access Perl variables and classes, and use TT directives. The rest of 
+the template is normal HTML. Change the hello method in Root.pm to the 
+following:
 
-=item *
-
-L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
-
-C<Static::Simple> provides an easy method of serving static content such
-as images and CSS files under the development server.
-
-=back
-
-To modify the list of plugins, edit C<lib/MyApp.pm> (this file is
-generally referred to as your I<application class>) and delete the line
-with:
-
-    use Catalyst qw/-Debug ConfigLoader Static::Simple/;
-
-Replace it with:
-
-    use Catalyst qw/
-            -Debug
-            ConfigLoader
-            Static::Simple
-            
-            StackTrace
-            /;
-
-This tells Catalyst to start using one new plugin:
-
-=over 4
-
-=item * 
-
-L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
-
-Adds a stack trace to the standard Catalyst "debug screen" (this is the
-screen Catalyst sends to your browser when an error occurs).
-
-Note: 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.
-
-=back
-
-Note that when specifying plugins on the C<use Catalyst> 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.
-
-B<TIP:> You may see examples that include the
-L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
-plugins.  As of Catalyst 5.7000, C<DefaultEnd> has been
-deprecated in favor of 
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
-(as the name of the package suggests, C<RenderView> is not
-a plugin, but an action). The purpose of both is essentially the same: 
-forward processing to the view to be rendered.  Applications generated
-under 5.7000 should automatically use C<RenderView> and "just work"
-for most applications.  For more information on C<RenderView> and 
-the various options for forwarding to your view logic, please refer 
-to the "Using RenderView for the Default View" section under 
-"CATALYST VIEWS" below.
-
-
-=head1 DATABASE ACCESS WITH C<DBIx::Class>
-
-Catalyst can be used with virtually any form of persistent datastore
-available via Perl.  For example, 
-L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to
-easily access databases through the traditional Perl C<DBI> interface.
-However, most Catalyst applications use some form of ORM technology to
-automatically create and save model objects as they are used.  Although
-Tony Bowden's L<Class::DBI|Class::DBI> has been the traditional 
-Perl ORM engine, 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.
-
-Note: See L<Catalyst::Model::CDBI> for more information on using
-Catalyst with L<Class::DBI|Class::DBI>.
-
-=head2 Create a DBIC Schema File
-
-DBIx::Class uses a schema file to load other classes that represent the
-tables in your database (DBIC refers to these "table objects" as "result
-sources"; see L<DBIx::Class::ResultSource>).  In this case, we want to
-load the model object for the C<books>, C<book_authors>, and C<authors>
-tables created in the previous step.
-
-Create C<lib/MyAppDB.pm> in your editor and insert:
-
-    package MyAppDB;
-    
-    =head1 NAME 
-    
-    MyAppDB - DBIC Schema Class
-    
-    =cut
-    
-    # Our schema needs to inherit from 'DBIx::Class::Schema'
-    use base qw/DBIx::Class::Schema/;
-    
-    # Need to load the DB Model classes here.
-    # You can use this syntax if you want:
-    #    __PACKAGE__->load_classes(qw/Book BookAuthor Author/);
-    # Also, if you simply want to load all of the classes in a directory
-    # of the same name as your schema class (as we do here) you can use:
-    #    __PACKAGE__->load_classes(qw//);
-    # But the variation below is more flexible in that it can be used to 
-    # load from multiple namespaces.
-    __PACKAGE__->load_classes({
-        MyAppDB => [qw/Book BookAuthor Author/]
-    });
-    
-    1;
-
-B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
-of the package where it is used.  Therefore, in C<MyAppDB.pm>,
-C<__PACKAGE__> is equivalent to C<MyAppDB>.
-
-B<Note:> 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 as shown above.
-
-
-=head2 Create the DBIC "Result Source" Files
-
-In this step, we create "table classes" (again, these are called a
-"result source" classes in DBIC) that act as model objects for the
-C<books>, C<book_authors>, and C<authors> tables in our database.
-
-First, create a directory to hold the class:
-
-    $ mkdir lib/MyAppDB
-
-Then create C<lib/MyAppDB/Book.pm> in your editor and enter:
-
-    package MyAppDB::Book;
-    
-    use base qw/DBIx::Class/;  
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('books');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/id title rating/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key(qw/id/);
-    
-    #
-    # 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
-    __PACKAGE__->has_many(book_authors => 'MyAppDB::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(authors => 'book_authors', 'author');
-    
-    
-    =head1 NAME
-    
-    MyAppDB::Book - A model object representing a book.
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'books' table of your application
-    database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    Offline utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
-
-This 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 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.
-
-Next, create C<lib/MyAppDB/Author.pm> in your editor and enter:
-
-    package MyAppDB::Author;
-    
-    use base qw/DBIx::Class/;
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('authors');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/id first_name last_name/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key(qw/id/);
-    
-    #
-    # 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
-    __PACKAGE__->has_many(book_author => 'MyAppDB::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(books => 'book_author', 'book');
-    
-    
-    =head1 NAME
-    
-    MyAppDB::Author - A model object representing an author of a book (if a book has 
-    multiple authors, each will be represented be separate Author object).
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'authors' table of your application
-    database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    Offline utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
-
-Finally, create C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
-
-    package MyAppDB::BookAuthor;
-    
-    use base qw/DBIx::Class/;
-    
-    # Load required DBIC stuff
-    __PACKAGE__->load_components(qw/PK::Auto Core/);
-    # Set the table name
-    __PACKAGE__->table('book_authors');
-    # Set columns in table
-    __PACKAGE__->add_columns(qw/book_id author_id/);
-    # Set the primary key for the table
-    __PACKAGE__->set_primary_key(qw/book_id author_id/);
-    
-    #
-    # 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 => 'MyAppDB::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 => 'MyAppDB::Author', 'author_id');
-    
-    
-    =head1 NAME
-    
-    MyAppDB::BookAuthor - A model object representing the JOIN between an author and 
-    a book.
-    
-    =head1 DESCRIPTION
-    
-    This is an object that represents a row in the 'book_authors' table of your 
-    application database.  It uses DBIx::Class (aka, DBIC) to do ORM.
-    
-    You probably won't need to use this class directly -- it will be automatically
-    used by DBIC where joins are needed.
-    
-    For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
-    Offline utilities may wish to use this class directly.
-    
-    =cut
-    
-    1;
-
-B<Note:> This sample application uses a plural form for the database
-tables (e.g., C<books> and C<authors>) and a singular form for the model
-objects (e.g., C<Book> and C<Author>); however, Catalyst places no
-restrictions on the naming conventions you wish to use.
-
-=head2 Use C<Catalyst::Model::DBIC::Schema> To Load The Model Class
-
-When L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> is
-in use, Catalyst essentially reads an existing copy of your database
-model and creates a new set of objects under C<MyApp::Model> for use
-inside of Catalyst.
-
-B<Note:> With 
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> you 
-essentially end up with two sets of model classes (only one of which 
-you write... the other set is created automatically in memory when 
-your Catalyst application initializes).  For this tutorial application, 
-the important points to remember are: you write the I<result source> 
-files in C<MyAppDB>, but I<within Catalyst> you use the I<automatically 
-created model classes> in C<MyApp::Model>.
-
-Use the 
-L<Catalyst::Helper::Model::DBIC::Schema|Catalyst::Helper::Model::DBIC::Schema> 
-helper script to create the model class that loads up the model we 
-created in the previous step:
-
-    $ script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB dbi:SQLite:myapp.db '' '' '{ AutoCommit => 1 }'
-     exists "/root/dev/MyApp/script/../lib/MyApp/Model"
-     exists "/root/dev/MyApp/script/../t"
-    created "/root/dev/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
-    created "/root/dev/MyApp/script/../t/model_MyAppDB.t"
-
-
-Where the first C<MyAppDB> is the name of the class to be created by the
-helper in C<lib/MyApp/Model> and the second C<MyAppDB> is the name of
-existing schema file we created (in C<lib/MyAppDB.pm>).  You can see
-that the helper creates a model file under C<lib/MyApp/Model> (Catalyst
-has a separate directory under C<lib/MyApp> for each of the three parts
-of MVC: C<Model>, C<View>, and C<Controller> [although older Catalyst
-applications often use the directories C<M>, C<V>, and C<C>]).
-
-
-=head1 CREATE A CATALYST CONTROLLER
-
-Controllers are where you write methods that interact with user
-input--typically, controller methods respond to C<GET> and C<POST>
-messages from the user's web browser.
-
-Use the Catalyst C<create> script to add a controller for book-related
-actions:
-
-    $ script/myapp_create.pl controller Books
-     exists "/root/dev/MyApp/script/../lib/MyApp/Controller"
-     exists "/root/dev/MyApp/script/../t"
-    created "/root/dev/MyApp/script/../lib/MyApp/Controller/Books.pm"
-    created "/root/dev/MyApp/script/../t/controller_Books.t"
-
-Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
-to the controller:
-
-    =head2 list
-    
-    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
-    =cut
-     
-    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('MyAppDB::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';
+    sub hello : Global {
+        my ( $self, $c ) = @_;
+        $c->stash->{template} = 'hello.tt';
     }
 
-B<Note:> Programmers experienced with object-oriented Perl should
-recognize C<$self> as a reference to the object where this method was
-called.  On the other hand, C<$c> will be new to many Perl programmers
-who have not used Catalyst before (it's sometimes written as
-C<$context>).  The Context object is automatically passed to all
-Catalyst components.  It is used to pass information between components
-and provide access to Catalyst and plugin functionality.
+This time, instead of doing C<$c->response->body()>, you are setting 
+the value of the "template" hash key in the Catalyst "stash", an area 
+for putting information to share with other parts of your application. 
+The "template" key determines which template will be displayed at the 
+end of the method. Catalyst controllers have a default "end" action 
+for all methods which causes the first (or default) view to be 
+rendered (unless there's a C<$c->response->body()> statement). So your 
+template will be magically displayed at the end of your method.
 
-B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above
-written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>.  The two
-are equivalent.
+After saving the file, restart the development server, and look at 
+L<http://localhost:3000/hello|http://localhost:3000> again. You should 
+see the template that you just made.
 
-B<Note:> Catalyst actions are regular Perl methods, but they make use of
-Nicholas Clark's C<attributes> module (that's the C<: Local> next to the
-C<sub list> in the code above) to provide additional information to the 
-Catalyst dispatcher logic.
 
+=head1 CREATE A SIMPLE CONTROLLER AND AN ACTION
 
-=head1 CATALYST VIEWS
+Create a controller named "Site" by executing the create script:
 
-Views are where you render output, typically for display in the user's
-web browser, but also possibly using other display output-generation
-systems.  As with virtually every aspect of Catalyst, options abound
-when it comes to the specific view technology you adopt inside your
-application.  However, most Catalyst applications use the Template
-Toolkit, known as TT (for more information on TT, see
-L<http://www.template-toolkit.org>). Other popular view technologies
-include Mason (L<http://www.masonhq.com> and
-L<http://www.masonbook.com>) and L<HTML::Template|HTML::Template>
-(L<http://html-template.sourceforge.net>).
+    $ script/hello_create.pl controller Site
 
-=head2 Create a Catalyst View Using C<TTSite>
+This will create a C<lib/Hello/Controller/Site.pm> file (and a test 
+file). Bring Site.pm up in your editor, and you can see that there's 
+not much there. Most people probably don't bother to use the create 
+script to make controllers after they're used to using Catalyst.
 
-When using TT for the Catalyst view, there are two main helper scripts:
+In Site.pm, add the following method:
 
-=over 4
-
-=item *
-
-L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
-
-=item *
-
-L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
-
-=back
-
-Both are similar, but C<TT> merely 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 Part 7). The C<TTSite> helper 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 TTSite is useful to bootstrap a project, we recommend that
-unless you know what your're doing or want to pretty much use the
-supplied templates as is, that you use the plain Template Toolkit view
-when starting a project from scratch.  This is because TTSite can be
-tricky to customize.  Additionally TT contains constructs that you
-need to learn yourself if you're going to be a serious user of TT.
-Our experience suggests that you're better off learning these from
-scratch.  We use TTSite here precisely because it is useful for
-bootstrap/prototype purposes.
-
-Enter the following command to enable the C<TTSite> style of view
-rendering for this tutorial:
-
-    $ script/myapp_create.pl view TT TTSite
-     exists "/root/dev/MyApp/script/../lib/MyApp/View"
-     exists "/root/dev/MyApp/script/../t"
-    created "/root/dev/MyApp/script/../lib/MyApp/View/TT.pm"
-    created "/root/dev/MyApp/script/../root/lib"
-    ...
-    created "/root/dev/MyApp/script/../root/src/ttsite.css"
-
-This puts a number of files in the C<root/lib> and C<root/src>
-directories that can be used to customize the look and feel of your
-application.  Also take a look at C<lib/MyApp/View/TT.pm> for config
-values set by the C<TTSite> helper.
-
-B<TIP>: Note that TTSite does one thing that could confuse people who
-are used to the normal C<TT> Catalyst view: it redefines the Catalyst
-context object in templates from its usual C<c> to C<Catalyst>. When
-looking at other Catalyst examples, remember that they almost always use
-C<c>.  Note that Catalyst and TT I<do not complain> when you use the
-wrong name to access the context object...TT simply outputs blanks for
-that bogus logic (see next tip to change this behavior with TT C<DEBUG>
-options).  Finally, be aware that this change in name I<only>
-applies to how the context object is accessed inside your TT templates;
-your controllers will continue to use C<$c> (or whatever name you use
-when fetching the reference from C<@_> inside your methods). (You can
-change back to the "default" behavior be removing the C<CATALYST_VAR>
-line from C<lib/MyApp/View/TT.pm>, but you will also have to edit
-C<root/lib/config/main> and C<root/lib/config/url>.  If you do this, be
-careful not to have a collision between your own C<c> variable and the
-Catalyst C<c> variable.)
-
-B<TIP>: When troubleshooting TT it can be helpful to enable variable
-C<DEBUG> options.  You can do this in a Catalyst environment by adding
-a C<DEBUG> line to the C<__PACKAGE__->config> declaration in 
-C<lib/MyApp/View/TT.pm>:
-
-    __PACKAGE__->config({
-        CATALYST_VAR => 'Catalyst',
-        ...
-        DEBUG        => 'undef',
-        ...
-    });
-
-There are a variety of options you can use, such as 'undef', 'all', 
-'service', 'context', 'parser', 'provider', and 'service'.  See
-L<Template::Constants> for more information (remove the C<DEBUG_>
-portion of the name shown in the TT docs and convert to lower case
-for use inside Catalyst).
-
-B<NOTE:> Please be sure to disable TT debug options before 
-continuing the tutorial (especially the 'undef' option -- leaving
-this enabled will conflict with several of the conventions used
-by this tutorial and TTSite to leave some variables undefined
-on purpose).
-
-
-=head2 Using C<RenderView> for the Default View
-
-Once your controller logic has processed the request from a user, it 
-forwards processing to your view in order to generate the appropriate 
-response output.  Catalyst v5.7000 ships with a new mechanism, 
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>, that 
-automatically performs this operation.  If you look in 
-C<lib/MyApp/Controller/Root.pm>, you should see the empty 
-definition for the C<sub end> method:
-
-    sub end : ActionClass('RenderView') {}
-
-The following bullet points provide a quick overview of the 
-C<RenderView> process:
-
-=over 4
-
-=item *
-
-C<Root.pm> is designed to hold application-wide logic.
-
-=item *
-
-At the end of a given user request, Catalyst will call the most specific 
-C<end> method that's appropriate.  For example, if the controller for a 
-request has an C<end> method defined, it will be called.  However, if 
-the controller does not define a controller-specific C<end> method, the 
-"global" C<end> method in C<Root.pm> will be called.
-
-=item *
-
-Because the definition includes an C<ActionClass> attribute, the
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
-will be executed B<after> any code inside the definition of C<sub end>
-is run.  See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
-for more information on C<ActionClass>.
-
-=item *
-
-Because C<sub end> is empty, this effectively just runs the default 
-logic in C<RenderView>.  However, you can easily extend the 
-C<RenderView> logic by adding your own code inside the empty method body 
-(C<{}>) created by the Catalyst Helpers when we first ran the 
-C<catalyst.pl> to initialize our application.  See 
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more 
-detailed information on how to extended C<RenderView> in C<sub end>.
-
-=back
-
-
-=head3 The History Leading Up To C<RenderView>
-
-Although C<RenderView> strikes a nice balance between default
-behavior and easy extensibility, it is a new feature that won't 
-appear in most existing Catalyst examples.  This section provides
-some brief background on the evolution of default view rendering
-logic with an eye to how they can be migrated to C<RenderView>:
-
-=over 4
-
-=item *
-
-Private C<end> Action in Application Class
-
-Older Catalyst-related documents often suggest that you add a "private 
-end action" to your application class (C<MyApp.pm>) or Root.pm 
-(C<MyApp/Controller/Root.pm>).  These examples should be easily 
-converted to L<RenderView|Catalyst::Action::RenderView> by simply adding 
-the attribute C<:ActionClass('RenderView')> to the C<sub end> 
-definition. If end sub is defined in your application class 
-(C<MyApp.pm>), you should also migrate it to 
-C<MyApp/Controller/Root.pm>.
-
-=item *
-
-L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
-
-C<DefaultEnd> represented the "next step" in passing processing from 
-your controller to your view.  It has the advantage of only requiring 
-that C<DefaultEnd> be added to the list of plugins in C<lib/MyApp.pm>. 
-It also allowed you to add "dump_info=1" (precede with "?" or "&" 
-depending on where it is in the URL) to I<force> the debug screen at the 
-end of the Catalyst request processing cycle.  However, it was more 
-difficult to extend than the C<RenderView> mechanism, and is now 
-deprecated.
-
-=item *
-
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
-
-As discussed above, the current recommended approach to handling your 
-view logic relies on 
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>.  Although 
-similar in first appearance to the "private end action" approach, it 
-utilizes Catalyst's "ActionClass" mechanism to provide both automatic 
-default behavior (you don't have to include a plugin as with 
-C<DefaultEnd>) and easy extensibility.  As with C<DefaultEnd>, it allows 
-you to add "dump_info=1" (precede with "?" or "&" depending on where it 
-is in the URL) to I<force> the debug screen at the end of the Catalyst 
-request processing cycle.
-
-=back
-
-It is recommended that all Catalyst applications use or migrate to
-the C<RenderView> approach.
-
-
-=head2 Globally Customize Every View
-
-When using TTSite, files in the subdirectories of C<root/lib> can be
-used to make changes that will appear in every view.  For example, to
-display optional status and error messages in every view, edit
-C<root/lib/site/layout>, updating it to match the following (the two HTML
-C<span> elements are new):
-
-    <div id="header">[% PROCESS site/header %]</div>
-    
-    <div id="content">
-    <span class="message">[% status_msg %]</span>
-    <span class="error">[% error_msg %]</span>
-    [% content %]
-    </div>
-    
-    <div id="footer">[% PROCESS site/footer %]</div>
-
-If we set either message in the Catalyst stash (e.g.,
-C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
-be displayed whenever any view used by that request is rendered.  The
-C<message> and C<error> CSS styles are automatically defined in
-C<root/src/ttsite.css> and can be customized to suit your needs.
-
-B<Note:> The Catalyst stash only lasts for a single HTTP request.  If
-you need to retain information across requests you can use
-L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
-Catalyst sessions in the Authentication part of the tutorial).
-
-
-=head2 Create a TT Template Page
-
-To add a new page of content to the TTSite view hierarchy, just create a
-new C<.tt2> file in C<root/src>.  Only include HTML markup that goes
-inside the HTML <body> and </body> tags, TTSite will use the contents of
-C<root/lib/site> to add the top and bottom.
-
-First create a directory for book-related TT templates:
-
-    $ mkdir root/src/books
-
-Then create C<root/src/books/list.tt2> in your editor and enter:
-
-    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
-    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
-    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
-    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
-    
-    [% # Provide a title to root/lib/site/header -%]
-    [% META title = 'Book List' -%]
-    
-    <table>
-    <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
-    [% # Display each book in a table row %]
-    [% FOREACH book IN books -%]
-      <tr>
-        <td>[% book.title %]</td>
-        <td>[% book.rating %]</td>
-        <td>
-          [% # 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      -%]
-          [% # 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.                                 -%]
-          [% 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   -%]
-          ([% tt_authors.size %])
-          [% # Use another TT vmethod to join & print the names & comma separators   -%]
-          [% tt_authors.join(', ') %]
-        </td>
-      </tr>
-    [% END -%]
-    </table>
-
-As indicated by the inline comments above, the C<META title> line uses
-TT's META feature to provide a title to C<root/lib/site/header>.
-Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
-object and prints the C<title> and C<rating> fields.  An inner
-C<FOREACH> loop prints the last name of each author in a comma-separated
-list within a single table cell.
-
-If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
-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 applies to operations as diverse as method calls, hash lookups, and
-list index values (see
-L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
-for details and examples).  In addition to the usual C<Template> module
-Pod documentation, you can access the TT manual at
-L<http://www.template-toolkit.org/docs/default/>.
-
-B<NOTE>: The C<TTSite> helper creates several TT files using an
-extension of C<.tt2>. Most other Catalyst and TT examples use an
-extension of C<.tt>.  You can use either extension (or no extension at
-all) with TTSite and TT, just be sure to use the appropriate extension
-for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
-...> line in your controller.  This document will use C<.tt2> for
-consistency with the files already created by the C<TTSite> helper.
-
-
-=head1 RUN THE APPLICATION
-
-First, let's enable an environment variable option that causes
-DBIx::Class to dump the SQL statements it's using to access the database
-(this option can provide extremely helpful troubleshooting information):
-
-    $ export DBIC_TRACE=1
-
-B<NOTE>: You can also use the older 
-C<export DBIX_CLASS_STORAGE_DBI_DEBUG=1>, but that's a lot more to
-type.
-
-This assumes you are using BASH as your shell -- adjust accordingly if
-you are using a different shell (for example, under tcsh, use
-C<setenv DBIX_CLASS_STORAGE_DBI_DEBUG 1>).
-
-B<NOTE>: You can also set this in your code using
-C<$class-E<gt>storage-E<gt>debug(1);>.  See
-L<DBIx::Class::Manual::Troubleshooting> for details (including options
-to log to file instead of displaying to the Catalyst development server
-log).
-
-Then run the Catalyst "demo server" script:    
-
-    $ script/myapp_server.pl
-
-Your development server log output should display something like:
-
-    $ script/myapp_server.pl
-    [debug] Debug messages enabled
-    [debug] Loaded plugins:
-    .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.13                                       |
-    | Catalyst::Plugin::StackTrace  0.06                                         |
-    | Catalyst::Plugin::Static::Simple  0.14                                     |
-    '----------------------------------------------------------------------------'
-    
-    [debug] Loaded dispatcher "Catalyst::Dispatcher"
-    [debug] Loaded engine "Catalyst::Engine::HTTP"
-    [debug] Found home "/home/me/MyApp"
-    [debug] Loaded Config "/home/me/myapp.yml"
-    [debug] Loaded components:
-    .-----------------------------------------------------------------+----------.
-    | Class                                                           | Type     |
-    +-----------------------------------------------------------------+----------+
-    | MyApp::Controller::Books                                        | instance |
-    | MyApp::Controller::Root                                         | instance |
-    | MyApp::Model::MyAppDB                                           | instance |
-    | MyApp::Model::MyAppDB::Author                                   | class    |
-    | MyApp::Model::MyAppDB::Book                                     | class    |
-    | MyApp::Model::MyAppDB::BookAuthor                               | class    |
-    | MyApp::View::TT                                                 | instance |
-    '-----------------------------------------------------------------+----------'
-    
-    [debug] Loaded Private actions:
-    .----------------------+--------------------------------------+--------------.
-    | Private              | Class                                | Method       |
-    +----------------------+--------------------------------------+--------------+
-    | /default             | MyApp::Controller::Root              | default      |
-    | /end                 | MyApp::Controller::Root              | end          |
-    | /books/index         | MyApp::Controller::Books             | index        |
-    | /books/list          | MyApp::Controller::Books             | list         |
-    '----------------------+--------------------------------------+--------------'
-    
-    [debug] Loaded Path actions:
-    .-------------------------------------+--------------------------------------.
-    | Path                                | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /books/list                         | /books/list                          |
-    '-------------------------------------+--------------------------------------'
-    
-    [info] MyApp powered by Catalyst 5.7002
-    You can connect to your server at http://localhost:3000
-
-Some things you should note in the output above:
-
-=over 4
-
-=item * 
-
-Catalyst::Model::DBIC::Schema took our C<MyAppDB::Book> and made it
-C<MyApp::Model::MyAppDB::Book> (and similar actions were performed on
-C<MyAppDB::Author> and C<MyAppDB::BookAuthor>).
-
-=item * 
-
-The "list" action in our Books controller showed up with a path of
-C</books/list>.
-
-=back
-
-Point your browser to L<http://localhost:3000> and you should still get
-the Catalyst welcome page.
-
-Next, to view the book list, change the URL in your browser to
-L<http://localhost:3000/books/list>. You should get a list of the five
-books loaded by the C<myapp01.sql> script above, with TTSite providing
-the formatting for the very simple output we generated in our template.
-The count and space-separated list of author last names appear on the
-end of each row.
-
-Also notice in the output of the C<script/myapp_server.pl> that DBIC
-used the following SQL to retrieve the data:
-
-    SELECT me.id, me.title, me.rating FROM books me
-
-Along with a list of the following commands to retrieve the authors for
-each book (the lines have been "word wrapped" here to improve
-legibility):
-
-    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'
-
-You should see 5 such lines of debug output as DBIC fetches the author 
-information for each book.
-
-
-=head1 USING THE DEFAULT TEMPLATE NAME
-
-By default, C<Catalyst::View::TT> will look for a template that uses the 
-same name as your controller action, allowing you to save the step of 
-manually specifying the template name in each action.  For example, this 
-would allow us to remove the 
-C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our 
-C<list> action in the Books controller.  Open 
-C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
-to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
-has changed):
-
-    =head2 list
-    
-    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
-    =cut
-    
-    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('MyAppDB::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';
+    sub test : Local {
+        my ( $self, $c ) = @_;
+        $c->stash->{username} = "John";
+        $c->stash->{template} = 'site/test.tt';
     }
 
-C<Catalyst::View::TT> defaults to looking for a template with no 
-extension.  In our case, we need to override this to look for an 
-extension of C<.tt2>.  Open C<lib/MyApp/View/TT.pm> and add the 
-C<TEMPLATE_EXTENSION> definition as follows:
+Notice the "Local" attribute on the method. This will allow the action 
+to be executed on the "controller/method" URL, or, in this case, 
+"site/test", instead of at the root site URL, like "Global". It's not 
+actually necessary to set the template value, since by default TT will 
+attempt to render a template that follows the naming pattern 
+"controller/method.tt", and we're following that pattern here, but in 
+other situations you will need to specify the template (such as if 
+you've "forwarded" to the method, or if it doesn't follow the default 
+naming convention). We've also put the variable "name" into the stash, 
+for use in the template.
 
-    __PACKAGE__->config({
-        CATALYST_VAR => 'Catalyst',
-        INCLUDE_PATH => [
-            MyApp->path_to( 'root', 'src' ),
-            MyApp->path_to( 'root', 'lib' )
-        ],
-        PRE_PROCESS  => 'config/main',
-        WRAPPER      => 'site/wrapper',
-        ERROR        => 'error.tt2',
-        TIMER        => 0,
-        TEMPLATE_EXTENSION => '.tt2',
-    });
+Make a subdirectory "site" in the "root" directory. Copy the hello.tt 
+file into the directory as root/site/test.tt, or create a new template 
+file at that location. Include a line like: 
 
-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.
+    <p>Hello, [% username %]!</p> 
 
-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
-the C<$c-E<gt>detach> mechanisms (these are discussed in Part 2 and 
-Part 8 of the Tutorial).
+Bring up or restart the server.  Notice in the server output that 
+C</site/test> is listed in the Loaded Path actions. Go to 
+L<http://localhost:3000/site/test|http://localhosst:3000/site/test> 
 
+You should see your test.tt file displayed, including the name "John"
+that you set in the controller.
 
-=head1 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>:
+=head1 AUTHORS
 
-    $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.
-
-
-=head1 AUTHOR
-
+Gerda Shank, C<gerda.shank at gmail.com>
 Kennedy Clark, C<hkclark at 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/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
 
-Copyright 2006, Kennedy Clark, under Creative Commons License
+Copyright 2006, Kennedy Clark & Gerda Shank, under Creative Commons License
 (L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
-

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Debugging.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Debugging.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Debugging.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,10 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Debugging - Catalyst Tutorial - Part 6: Debugging
+Catalyst::Manual::Tutorial::Debugging - Catalyst Tutorial - Part 7: Debugging
 
+
 =head1 OVERVIEW
 
-This is B<Part 6 of 9> for the Catalyst tutorial.
+This is B<Part 7 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -20,30 +21,34 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-B<Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+B<Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
@@ -102,7 +107,7 @@
 you can obviously indent them if you prefer):
 
     sub list : Local {
-        # Retrieve the usual perl OO '$self' for this object. $c is the Catalyst
+        # 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) = @_;
@@ -111,7 +116,7 @@
             
         # 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('MyAppDB::Book')->all];
+        $c->stash->{books} = [$c->model('MyAppDB::Books')->all];
             
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods.
@@ -150,7 +155,7 @@
 development server will drop to the Perl debugger prompt:
 
     MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:40):
-    40:         $c->stash->{books} = [$c->model('MyAppDB::Book')->all];
+    40:         $c->stash->{books} = [$c->model('MyAppDB::Books')->all];
     
       DB<1>
 
@@ -172,7 +177,7 @@
 
 Next, list the methods available on our C<Book> model:
 
-      DB<1> m $c->model('MyAppDB::Book')
+      DB<1> m $c->model('MyAppDB::Books')
     ()
     (0+
     (bool
@@ -191,7 +196,7 @@
 
 We can also play with the model directly:
 
-      DB<2> x ($c->model('MyAppDB::Book')->all)[1]->title
+      DB<2> x ($c->model('MyAppDB::Books')->all)[1]->title
     SELECT me.id, me.title, me.rating FROM books me:
     0  'TCP/IP Illustrated, Volume 1'
 
@@ -249,6 +254,10 @@
 
     mkdir -p lib/Module; cp `perldoc -l Module::Name` lib/Module/
 
+Note: If you are following along in Ubuntu, you will need to install
+the C<perl-doc> package to use the C<perldoc> command.  Use 
+C<sudo apt-get install perl-doc> to do that.
+
 For example, you could make a copy of 
 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
 with the following command:
@@ -256,6 +265,9 @@
     mkdir -p lib/Catalyst/Plugin; cp \
         `perldoc -l Catalyst::Plugin::Authentication` lib/Catalyst/Plugin
 
+You can then use the local copy inside your project to place logging
+messages and/or breakpoints for further study of that module.
+
 B<Note:> Matt has also suggested the following tips for Perl 
 debugging:
 
@@ -282,7 +294,7 @@
 For example:
 
     $ perl -MCatalyst::Plugin::Authentication -e \
-        'print Catalyst::Plugin::Authentication->can("prepare");'
+        'print Catalyst::Plugin::Authentication->can("user");'
     CODE(0x9c8db2c)
 
 If the method exists, the Perl C<can> method returns a coderef.

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Intro.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Intro.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Intro.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -5,7 +5,7 @@
 
 =head1 OVERVIEW
 
-This is B<Part 1 of 10> for the Catalyst tutorial.
+This is B<Part 2 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -82,18 +82,24 @@
 inadvertently made any typographic errors, or accidentally skipped
 part of the tutorial.>
 
-Additionally, if you're reading this manual online, you can download
-the example program and all the necessary dependencies to
-your local machine by installing the C<Task::Catalyst::Tutorial>
-distribution from CPAN:
+B<NOTE: You can use any perl-supported OS and environment to run 
+Catalyst.> It should make little or no difference to Catalyst's 
+operation, but this tutorial has been written using Ubuntu 8.04 
+because that represents a quick and easy for most people to try out 
+Catalyst with virtually zero setup time and hassles.  See the Catalyst 
+installation section below for more information.
 
+If you're reading this manual online, you can download the example 
+program and all the necessary dependencies to your local machine by 
+installing the C<Task::Catalyst::Tutorial> distribution from CPAN:
+
      cpan Task::Catalyst::Tutorial
 
 This will also test to make sure the dependencies are working.  If you
 have trouble installing these, please ask for help on the #catalyst
 IRC channel, or the Catalyst mailing list.
 
-Subjects covered include:
+Subjects covered by the tutorial include:
 
 =over 4
 
@@ -272,7 +278,7 @@
 =head1 CATALYST INSTALLATION
 
 If approach in the wrong manner, it can be a daunting tasks to get
-Catalyst initally installed.  Although a compelling strength of
+Catalyst initially installed.  Although a compelling strength of
 Catalyst is that it makes use of many of the modules in the
 vast repository that is CPAN, this can complicate the installation
 process.  However, there are a growing number of methods 
@@ -296,19 +302,20 @@
 
 =item * 
 
-Download Ubuntu 8.04 (aka, Hardy Heron) and boot from the CD and/or
-image file, select your language, and then "Try Ubuntu without any
-changes to your computer."
+Download Ubuntu 8.04 (aka, Hardy Heron) Desktop edition and boot from 
+the CD and/or image file, select your language, and then "Try Ubuntu 
+without any changes to your computer."
 
 =item *
 
-Open a terminal session.
+Open a terminal session (click "Applications" in the upper-left 
+corner, then "Accessories," then "Terminal").
 
 =item *
 
 Add the 'universe' repositories:
 
-    sudo vi /etc/apt/sources.list
+    sudo gedit /etc/apt/sources.list
 
 And remove the comments from the lines under the comments about the
 'universe' repositories.
@@ -318,11 +325,18 @@
 Install Catalyst:
 
     sudo apt-get update
-    sudo apt-get upgrade
-    sudo apt-get install sqlite3 libdbd-sqlite3-perl libcatalyst-perl libcatalyst-modules-perl
+    sudo apt-get install libdbd-sqlite3-perl libcatalyst-perl libcatalyst-modules-perl
 
 Accept all of the dependencies.  Done.
 
+NOTE: If you are low on disk space after the above commands (use C<df /> 
+to tell), you can free up some space with 
+C<sudo rm /var/cache/apt/archives/*.deb> (the Live CD uses memory for 
+disk space, so having a decent amount of memory will help).  And, 
+while the instructions above mention the Live CD because that makes it 
+easy for people new to Linux, you can obviously also use one of the 
+options to install Ubuntu on your drive.
+
 =back
 
 =item * 

Added: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod	                        (rev 0)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -0,0 +1,1096 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::MoreCatalystBasics - Catalyst Tutorial - Part 3: More Catalyst Application Development Basics
+
+
+=head1 OVERVIEW
+
+This is B<Part 3 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
+
+=item 3
+
+B<More Catalyst Basics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This part of the tutorial builds on the work done in Part 2 to explore 
+some features that are more typical of "real world" web applications. 
+From this part of the tutorial onward, we will be building a simple 
+book database application.  Although the application will be too 
+limited to be of use to anyone, it should provide a basic environment 
+where we can explore a variety of features used in virtually all web 
+applications.
+
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::Intro>
+
+
+=head1 CREATE A NEW APPLICATION
+
+The remainder of the tutorial will build an application call C<MyApp>. 
+Use the Catalyst C<catalyst.pl> script to initialize the framework for 
+an application called C<MyApp> (make sure you aren't still inside the 
+directory of the C<Hello> application from the previous part of the 
+tutorial):
+
+    $ catalyst.pl MyApp
+    created "MyApp"
+    created "MyApp/script"
+    created "MyApp/lib"
+    created "MyApp/root"
+    ...
+    created "MyApp/script/myapp_create.pl"
+    $ cd MyApp
+
+This creates a similar skeletal structure to what we saw in Part 2 of 
+the tutorial, except with C<MyApp> or C<myapp> substituted for 
+C<Hello> and C<hello>.
+
+
+=head1 EDIT THE LIST OF CATALYST PLUGINS
+
+One of the greatest benefits of Catalyst is that it has such a large
+library of plugins 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.
+
+By default, Catalyst enables three plugins/flags:
+
+=over 4
+
+=item * 
+
+C<-Debug> Flag
+
+Enables the Catalyst debug output you saw when we started the
+C<script/myapp_server.pl> development server earlier.  You can remove
+this plugin when you place your application into production.
+
+As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
+Although most of the items specified on the C<use Catalyst> 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.
+
+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
+to C<script/myapp_server.pl> to re-enable it just for the development
+server.  We will not be using that approach in the tutorial, but feel 
+free to make use of it in your own projects.
+
+=item *
+
+L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
+
+C<ConfigLoader> provides an automatic way to load configurable
+parameters for your application from a central YAML file (versus having
+the values hard-coded inside your Perl modules).  If you have not been
+exposed to YAML before, it is a human-readable data serialization format
+that can be used to read (and write) values to/from text files.  We will
+see how to use this feature of Catalyst during the authentication and
+authorization sections (Part 5 and Part 6).
+
+=item *
+
+L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
+
+C<Static::Simple> provides an easy method of serving static content such
+as images and CSS files under the development server.
+
+=back
+
+To modify the list of plugins, edit C<lib/MyApp.pm> (this file is
+generally referred to as your I<application class>) and delete the line
+with:
+
+    use Catalyst qw/-Debug ConfigLoader Static::Simple/;
+
+Replace it with:
+
+    use Catalyst qw/
+            -Debug
+            ConfigLoader
+            Static::Simple
+            
+            StackTrace
+            /;
+
+This tells Catalyst to start using one new plugin:
+
+=over 4
+
+=item * 
+
+L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
+
+Adds a stack trace to the standard Catalyst "debug screen" (this is the
+screen Catalyst sends to your browser when an error occurs).
+
+Note: 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.
+
+=back
+
+Note that when specifying plugins on the C<use Catalyst> 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.
+
+
+=head1 CREATE A CATALYST CONTROLLER
+
+As discussed earlier, controllers are where you write methods that 
+interact with user input.  Typically, controller methods respond to 
+C<GET> and C<POST> messages from the user's web browser.
+
+Use the Catalyst C<create> script to add a controller for book-related
+actions:
+
+    $ script/myapp_create.pl controller Books
+     exists "/home/me/MyApp/script/../lib/MyApp/Controller"
+     exists "/home/me/MyApp/script/../t"
+    created "/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm"
+    created "/home/me/MyApp/script/../t/controller_Books.t"
+
+Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
+to the controller:
+
+    =head2 list
+    
+    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
+    
+    =cut
+     
+    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('MyAppDB::Books')->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';
+    }
+
+B<Note:> This won't actually work yet since you haven't set up your 
+model yet.
+
+B<Note:> Programmers experienced with object-oriented Perl should 
+recognize C<$self> as a reference to the object where this method was 
+called.  On the other hand, C<$c> will be new to many Perl programmers 
+who have not used Catalyst before (it's sometimes written as 
+C<$context>).  The Context object is automatically passed to all 
+Catalyst components.  It is used to pass information between 
+components and provide access to Catalyst and plugin functionality.
+
+B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above
+written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>.  The two
+are equivalent.
+
+B<Note:> Catalyst actions are regular Perl methods, but they make use 
+of Nicholas Clark's C<attributes> module (that's the C<: Local> next 
+to the C<sub list> in the code above) to provide additional 
+information to the Catalyst dispatcher logic.  Many newer Catalyst 
+applications are switching to the use of "Literal" C<: Path> actions 
+and C<Args> attribute in lieu of C<: Local> and C<: Private>.  For 
+example, C<sub any_method : Path Args(0)> can be used instead of 
+C<sub index :Private> (because no path was supplied to C<Path> it 
+matches the "empty" URL in the namespace of that module... the same 
+thing C<sub index> would do) or C<sub list : Path('list') Args(0)> 
+could be used instead of the C<sub list : Local> above (the C<list> 
+argument to C<Path> would make it match on the URL C<list> under 
+C<books>, the namespace of the current module).  See "Action Types" in 
+L<Catalyst::Manual::Intro|Catalyst::Manual::Intro> as well as Part 5 
+of this tutorial (Authentication) for additional information.  Another 
+popular but more advanced feature is C<Chained> actions that allow a 
+single URL to "chain together" multiple action method calls, each with 
+an appropriate number of arguments (see
+L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>
+for details).
+
+
+=head1 CATALYST VIEWS
+
+As mentioned in Part 2 of the tutorial, views are where you render 
+output, typically for display in the user's web browser, but also 
+possibly using other display output- generation systems.  As with 
+virtually every aspect of Catalyst, options abound when it comes to 
+the specific view technology you adopt inside your application. 
+However, most Catalyst applications use the Template Toolkit, known as 
+TT (for more information on TT, see L<http://www.template-
+toolkit.org>). Other popular view technologies include Mason 
+(L<http://www.masonhq.com> and L<http://www.masonbook.com>) and 
+L<HTML::Template|HTML::Template> (L<http://html-
+template.sourceforge.net>).
+
+=head2 Create a Catalyst View Using C<TTSite>
+
+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 are similar, but C<TT> merely 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 Part 8). The C<TTSite> helper 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 TTSite is useful to bootstrap a project, we recommend that
+unless you know what you're doing or want to pretty much use the
+supplied templates as is, that you use the plain Template Toolkit view
+when starting a project from scratch.  This is because TTSite can be
+tricky to customize.  Additionally TT contains constructs that you
+need to learn yourself if you're going to be a serious user of TT.
+Our experience suggests that you're better off learning these from
+scratch.  We use TTSite here precisely because it is useful for
+bootstrap/prototype purposes.
+
+Enter the following command to enable the C<TTSite> style of view
+rendering for this tutorial:
+
+    $ script/myapp_create.pl view TT TTSite
+     exists "/home/me/MyApp/script/../lib/MyApp/View"
+     exists "/home/me/MyApp/script/../t"
+    created "/home/me/MyApp/script/../lib/MyApp/View/TT.pm"
+    created "/home/me/MyApp/script/../root/lib"
+    ...
+    created "/home/me/MyApp/script/../root/src/ttsite.css"
+
+This puts a number of files in the C<root/lib> and C<root/src>
+directories that can be used to customize the look and feel of your
+application.  Also take a look at C<lib/MyApp/View/TT.pm> for config
+values set by the C<TTSite> helper.
+
+B<TIP>: Note that TTSite does one thing that could confuse people who
+are used to the normal C<TT> Catalyst view: it redefines the Catalyst
+context object in templates from its usual C<c> to C<Catalyst>. When
+looking at other Catalyst examples, remember that they almost always use
+C<c>.  Note that Catalyst and TT I<do not complain> when you use the
+wrong name to access the context object...TT simply outputs blanks for
+that bogus logic (see next tip to change this behavior with TT C<DEBUG>
+options).  Finally, be aware that this change in name I<only>
+applies to how the context object is accessed inside your TT templates;
+your controllers will continue to use C<$c> (or whatever name you use
+when fetching the reference from C<@_> inside your methods). (You can
+change back to the "default" behavior be removing the C<CATALYST_VAR>
+line from C<lib/MyApp/View/TT.pm>, but you will also have to edit
+C<root/lib/config/main> and C<root/lib/config/url>.  If you do this, be
+careful not to have a collision between your own C<c> variable and the
+Catalyst C<c> variable.)
+
+B<TIP>: When troubleshooting TT it can be helpful to enable variable
+C<DEBUG> options.  You can do this in a Catalyst environment by adding
+a C<DEBUG> line to the C<__PACKAGE__->config> declaration in 
+C<lib/MyApp/View/TT.pm>:
+
+    __PACKAGE__->config({
+        CATALYST_VAR => 'Catalyst',
+        ...
+        DEBUG        => 'undef',
+        ...
+    });
+
+B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
+of the package where it is used.  Therefore, in C<TT.pm>,
+C<__PACKAGE__> is equivalent to C<TT>.
+
+There are a variety of options you can use, such as 'undef', 'all', 
+'service', 'context', 'parser', 'provider', and 'service'.  See
+L<Template::Constants> for more information (remove the C<DEBUG_>
+portion of the name shown in the TT docs and convert to lower case
+for use inside Catalyst).
+
+B<NOTE:> B<Please be sure to disable TT debug options before 
+continuing the tutorial> (especially the 'undef' option -- leaving
+this enabled will conflict with several of the conventions used
+by this tutorial and TTSite to leave some variables undefined
+on purpose).
+
+
+=head2 Globally Customize Every View
+
+When using TTSite, files in the subdirectories of C<root/lib> can be
+used to make changes that will appear in every view.  For example, to
+display optional status and error messages in every view, edit
+C<root/lib/site/layout>, updating it to match the following (the two HTML
+C<span> elements are new):
+
+    <div id="header">[% PROCESS site/header %]</div>
+    
+    <div id="content">
+    <span class="message">[% status_msg %]</span>
+    <span class="error">[% error_msg %]</span>
+    [% content %]
+    </div>
+    
+    <div id="footer">[% PROCESS site/footer %]</div>
+
+If we set either message in the Catalyst stash (e.g.,
+C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
+be displayed whenever any view used by that request is rendered.  The
+C<message> and C<error> CSS styles are automatically defined in
+C<root/src/ttsite.css> and can be customized to suit your needs.
+
+B<Note:> The Catalyst stash only lasts for a single HTTP request.  If
+you need to retain information across requests you can use
+L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
+Catalyst sessions in the Authentication part of the tutorial).
+
+
+=head2 Create a TT Template Page
+
+To add a new page of content to the TTSite view hierarchy, just create a
+new C<.tt2> file in C<root/src>.  Only include HTML markup that goes
+inside the HTML <body> and </body> tags, TTSite will use the contents of
+C<root/lib/site> to add the top and bottom.
+
+First create a directory for book-related TT templates:
+
+    $ mkdir root/src/books
+
+Then create C<root/src/books/list.tt2> in your editor and enter:
+
+    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
+    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
+    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
+    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
+    
+    [% # Provide a title to root/lib/site/header -%]
+    [% META title = 'Book List' -%]
+    
+    <table>
+    <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
+    [% # Display each book in a table row %]
+    [% FOREACH book IN books -%]
+      <tr>
+        <td>[% book.title %]</td>
+        <td>[% book.rating %]</td>
+      </tr>
+    [% END -%]
+    </table>
+
+As indicated by the inline comments above, the C<META title> line uses
+TT's META feature to provide a title to C<root/lib/site/header>.
+Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
+object and prints the C<title> and C<rating> fields.  An inner
+C<FOREACH> loop prints the last name of each author in a comma-separated
+list within a single table cell.
+
+If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
+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 applies to operations as diverse as method calls, hash lookups, and
+list index values (see
+L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
+for details and examples).  In addition to the usual C<Template> module
+Pod documentation, you can access the TT manual at
+L<http://www.template-toolkit.org/docs/default/>.
+
+B<NOTE>: The C<TTSite> helper creates several TT files using an
+extension of C<.tt2>. Most other Catalyst and TT examples use an
+extension of C<.tt>.  You can use either extension (or no extension at
+all) with TTSite and TT, just be sure to use the appropriate extension
+for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
+...> line in your controller.  This document will use C<.tt2> for
+consistency with the files already created by the C<TTSite> helper.
+
+
+=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.  Open C<myapp01.sql>
+in your editor and enter:
+
+    --
+    -- Create a very simple database to hold book and author information
+    --
+    CREATE TABLE books (
+            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_id     INTEGER,
+            author_id   INTEGER,
+            PRIMARY KEY (book_id, author_id)
+    );
+    CREATE TABLE authors (
+            id          INTEGER PRIMARY KEY,
+            first_name  TEXT,
+            last_name   TEXT
+    );
+    ---
+    --- 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);
+
+B<TIP>: See Appendix 1 for tips on removing the leading spaces when
+cutting and pasting example code from POD-based documents.
+
+Then use the following command to build a C<myapp.db> SQLite database:
+
+    $ sqlite3 myapp.db < myapp01.sql
+
+If you need to create the database more than once, you probably want to
+issue the C<rm myapp.db> command to delete the database before you use
+the C<sqlite3 myapp.db < myapp01.sql> command.
+
+Once the C<myapp.db> database file has been created and initialized, you
+can use the SQLite command line environment to do a quick dump of the
+database contents:
+
+    $ sqlite3 myapp.db
+    SQLite version 3.4.2
+    Enter ".help" for instructions
+    sqlite> select * from books;
+    1|CCSP SNRS Exam Certification Guide|5
+    2|TCP/IP Illustrated, Volume 1|5
+    3|Internetworking with TCP/IP Vol.1|4
+    4|Perl Cookbook|5
+    5|Designing with Web Standards|5
+    sqlite> .q
+    $
+
+Or:
+
+    $ sqlite3 myapp.db "select * from books"
+    1|CCSP SNRS Exam Certification Guide|5
+    2|TCP/IP Illustrated, Volume 1|5
+    3|Internetworking with TCP/IP Vol.1|4
+    4|Perl Cookbook|5
+    5|Designing with Web Standards|5
+
+As with most other SQL tools, if you are using the full "interactive"
+environment you need to terminate your SQL commands with a ";" (it's not
+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.
+
+
+=head1 DATABASE ACCESS WITH C<DBIx::Class>
+
+Catalyst can be used with virtually any form of persistent datastore
+available via Perl.  For example, 
+L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to
+easily access databases through the traditional Perl C<DBI> interface.
+However, most Catalyst applications use some form of ORM technology to
+automatically create and save model objects as they are used.  Although
+Tony Bowden's 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.
+
+=head2 Create a Dynamic DBIC Model
+
+Use the C<create=dynamic> model helper option to build a model that 
+dynamically reads your database structure every time the application
+starts:
+
+    $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=dynamic dbi:SQLite:myapp.db
+     exists "/home/me/MyApp/script/../lib/MyApp/Model"
+     exists "/home/me/MyApp/script/../t"
+    created "/home/me/MyApp/script/../lib/MyApp/Schema"
+    created "/home/me/MyApp/script/../lib/MyApp/Schema/MyAppDB.pm"
+    created "/home/me/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
+    created "/home/me/MyApp/script/../t/model_MyAppDB.t"
+
+
+C<MyAppDB> is the name of the model class to be created by the helper in 
+C<lib/MyApp/Model> (Catalyst has a separate directory under C<lib/MyApp> 
+for each of the three parts of MVC: C<Model>, C<View>, and C<Controller> 
+[although older Catalyst applications often use the directories C<M>, 
+C<V>, and C<C>]).  C<DBIC::Schema> is the type of the model to create. 
+C<MyApp::Schema::MyAppDB> is the name of the DBIC schema file written to 
+C<lib/MyApp/Schema/MyAppDB.pm>.  Because we specified C<create=dynamic> 
+to the helper, it use L<DBIx::Class::Schema::Loader> to dynamically load 
+the schema information from the database every time the application 
+starts.  And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect 
+string for use with SQLite.
+
+B<NOTE>: Although the C<create=dynamic> option to the DBIC helper 
+makes for a nifty demonstration, is not suitable for real world 
+applications. Moreover, it may not be supported in future versions of 
+DBIC.  After this demonstration, please use the C<create=static> 
+option that we switch to below.
+
+
+=head1 RUN THE APPLICATION
+
+First, let's enable an environment variable option that causes
+DBIx::Class to dump the SQL statements it's using to access the database
+(this option can provide extremely helpful troubleshooting information):
+
+    $ export DBIC_TRACE=1
+
+This assumes you are using BASH as your shell -- adjust accordingly if
+you are using a different shell (for example, under tcsh, use
+C<setenv DBIC_TRACE 1>).
+
+B<NOTE>: You can also set this in your code using
+C<$class-E<gt>storage-E<gt>debug(1);>.  See
+L<DBIx::Class::Manual::Troubleshooting> for details (including options
+to log to file instead of displaying to the Catalyst development server
+log).
+
+Then run the Catalyst "demo server" script:    
+
+    $ script/myapp_server.pl
+
+Your development server log output should display something like:
+
+    $script/myapp_server.pl
+    [debug] Debug messages enabled
+    [debug] Loaded plugins:
+    .----------------------------------------------------------------------------.
+    | Catalyst::Plugin::ConfigLoader  0.17                                       |
+    | Catalyst::Plugin::StackTrace  0.06                                         |
+    | Catalyst::Plugin::Static::Simple  0.20                                     |
+    '----------------------------------------------------------------------------'
+    
+    [debug] Loaded dispatcher "Catalyst::Dispatcher"
+    [debug] Loaded engine "Catalyst::Engine::HTTP"
+    [debug] Found home "/home/me/MyApp"
+    [debug] Loaded Config "/home/me/MyApp/myapp.yml"
+    [debug] Loaded components:
+    .-----------------------------------------------------------------+----------.
+    | Class                                                           | Type     |
+    +-----------------------------------------------------------------+----------+
+    | MyApp::Controller::Books                                        | instance |
+    | MyApp::Controller::Root                                         | instance |
+    | MyApp::Model::MyAppDB                                           | instance |
+    | MyApp::Model::MyAppDB::Authors                                  | class    |
+    | MyApp::Model::MyAppDB::BookAuthors                              | class    |
+    | MyApp::Model::MyAppDB::Books                                    | class    |
+    | MyApp::View::TT                                                 | instance |
+    '-----------------------------------------------------------------+----------'
+    
+    [debug] Loaded Private actions:
+    .----------------------+--------------------------------------+--------------.
+    | Private              | Class                                | Method       |
+    +----------------------+--------------------------------------+--------------+
+    | /default             | MyApp::Controller::Root              | default      |
+    | /end                 | MyApp::Controller::Root              | end          |
+    | /books/index         | MyApp::Controller::Books             | index        |
+    | /books/list          | MyApp::Controller::Books             | list         |
+    '----------------------+--------------------------------------+--------------'
+    
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /books/list                         | /books/list                          |
+    '-------------------------------------+--------------------------------------'
+    
+    [info] MyApp powered by Catalyst 5.7011
+    You can connect to your server at http://localhost:3000
+
+B<NOTE>: Be sure you run the C<script/myapp_server.pl> command from 
+the 'base' directory of your application, not inside the C<script> 
+directory itself or it will not be able to locate the C<myapp.db> 
+database file.  You can use a fully qualified or a relative path to 
+locate the database file, but we did not specify that when we ran the 
+model helper earlier.
+
+Some things you should note in the output above:
+
+=over 4
+
+=item * 
+
+Catalyst::Model::DBIC::Schema dynamically created three model classes, 
+one to represent each of the three tables in our database 
+(C<MyApp::Model::MyAppDB::Authors>, C<MyApp::Model::MyAppDB::BookAuthors>,
+and C<MyApp::Model::MyAppDB::Books>).
+
+=item * 
+
+The "list" action in our Books controller showed up with a path of
+C</books/list>.
+
+=back
+
+Point your browser to L<http://localhost:3000> and you should still get
+the Catalyst welcome page.
+
+Next, to view the book list, change the URL in your browser to
+L<http://localhost:3000/books/list>. You should get a list of the five
+books loaded by the C<myapp01.sql> script above, with TTSite providing
+the formatting for the very simple output we generated in our template.
+The rating for each book should appear on each row.
+
+Also notice in the output of the C<script/myapp_server.pl> that DBIC
+used the following SQL to retrieve the data:
+
+    SELECT me.id, me.title, me.rating FROM books me
+
+because we enabled DBIC_TRACE.
+
+You now the beginnings of a simple but workable web application. 
+Continue on to future sections and we will develop the application
+more fully.
+
+
+=head1 A STATIC DATABASE MODEL WITH C<DBIx::Class>
+
+=head2 Create Static DBIC Schema Files
+
+Unlike the previous section where we had DBIC 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 create a separate schema file for each table in
+the database, however, lets use the same L<DBIx::Class::Schema::Loader>
+used earlier with C<create=dynamic> to build the static files for us.
+First, lets remove the schema file created in Part 2:
+
+    $ rm lib/MyApp/Schema/MyAppDB.pm 
+
+Now regenerate the schema using the C<create=static> option:
+
+    $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db
+     exists "/home/me/MyApp/script/../lib/MyApp/Model"
+     exists "/home/me/MyApp/script/../t"
+    Dumping manual schema for MyApp::Schema::MyAppDB to directory /home/me/MyApp/script/../lib ...
+    Schema dump completed.
+     exists "/home/me/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
+
+We could have also deleted C<lib/MyApp/Model/MyAppDB.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/MyAppDB.pm>, it simply contains
+a reference to the actual schema file in C<lib/MyApp/Schema/MyAppDB.pm>
+along with the database connect string.
+
+If you look in the C<lib/MyApp/Schema> directory, you will find that 
+C<MyAppDB.pm> is no longer using L<DBIx::Class::Schema::Loader> as its 
+base class (L<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 that it only contains a call to the C<load_classes> method.  You 
+will also find that C<lib/MyApp/Schema> contains a C<MyAppDB> 
+subdirectory, with one file inside this directory for each of the tables 
+in our simple database (C<Authors.pm>, C<BookAuthors.pm>, and 
+C<Books.pm>).  These three files were created based on the information
+found by L<DBIx::Class::Schema::Loader> as the helper ran.
+
+The idea with all of the files created under C<lib/MyApp/Schema> 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 
+auto-generated 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/MyAppDB.pm>.  This file contains a reference to
+C<lib/MyApp/Schema/MyAppDB.pm>, so that file is loaded next.  Finally,
+the call to C<load_classes> in that file will load each of the 
+table-specific "results source" files from the C<lib/MyApp/Schema/MyAppDB>
+subdirectory.  These three table-specific DBIC schema files will then be 
+used to 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).
+
+
+=head2 Updating the Generated DBIC Schema Files
+
+
+Let's manually add some relationship information to the auto-generated
+schema files.  First edit C<lib/MyApp/Schema/MyAppDB/Books.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
+    __PACKAGE__->has_many(book_authors => 'MyApp::Schema::MyAppDB::BookAuthors', '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(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 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 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.
+
+Then edit C<lib/MyApp/Schema/MyAppDB/Authors.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 accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *foreign* table
+    __PACKAGE__->has_many(book_author => 'MyApp::Schema::MyAppDB::BookAuthors', '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(books => 'book_author', 'book');
+
+Finally, do the same for the "join table," 
+C<lib/MyApp/Schema/MyAppDB/BookAuthors.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::MyAppDB::Books', '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::MyAppDB::Authors', 'author_id');
+
+
+=head1 RUN THE APPLICATION
+
+Run the Catalyst "demo 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):
+
+    $ DBIC_TRACE=1 script/myapp_server.pl
+
+Make sure that the application loads correctly and that you see the 
+three dynamically created model class (one for each of the 
+table-specific schema classes we created).
+
+Then hit the URL L<http://localhost:3000/books/list> and be sure that
+the book list is displayed.
+
+
+=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
+
+In some situations, it can be useful to run your application and 
+display a page without using a browser.  Catalyst lets you do this 
+using the C<scripts/myapp_test.pl> script.  Just supply the URL you 
+wish to display and it will run that request through the normal 
+controller dispatch logic and use the appropriate view to render the 
+output (obviously, complex pages may dump a lot of text to your 
+terminal window).  For example, if you type:
+
+    $ script/myapp_test.pl "/books/list"
+
+You should get the same text as if you visited 
+L<http://localhost:3000/books/list> with the normal development server 
+and asked your browser to view the page source.
+
+
+=head1 UPDATING THE VIEW
+
+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> add 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<td> cells):
+
+    <td>
+      [% # 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      -%]
+      [% # 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.                                 -%]
+      [% 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   -%]
+      [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
+      ([% tt_authors.size | html %])
+      [% # Use another TT vmethod to join & print the names & comma separators   -%]
+      [% tt_authors.join(', ') | html %]
+    </td>
+
+Then hit C<Ctrl+R> in your browser (not that you don't need to reload 
+the development server or use the C<-r> option when updating TT 
+templates) and you should now the the number of authors each book and 
+a comma-separated list of the author's last names.  
+
+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).
+
+Also note that we are using "| html", a type of TT filter, to escape 
+characters such as E<lt> and E<gt> to &lt; and &gt; and avoid various
+types of dangerous hacks against your application.  In a real 
+application, you would probably want to put "| html" at the end of 
+every field where a user has control over the information that can 
+appear in that field (and can therefore inject markup or code if you
+don't "neutralize" those fields).  In addition to "| html", Template
+Toolkit has a variety of other useful filters that can found in the
+documentation for L<Template::Filters|Template::Filters>.
+
+
+=head2 Using C<RenderView> for the Default View
+
+B<NOTE: The rest of this part of the tutorial is optional.  You can 
+skip to Part 4, L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>, 
+if you wish.>
+
+Once your controller logic has processed the request from a user, it 
+forwards processing to your view in order to generate the appropriate 
+response output.  Catalyst uses
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> by 
+default to automatically performs this operation.  If you look in 
+C<lib/MyApp/Controller/Root.pm>, you should see the empty 
+definition for the C<sub end> method:
+
+    sub end : ActionClass('RenderView') {}
+
+The following bullet points provide a quick overview of the 
+C<RenderView> process:
+
+=over 4
+
+=item *
+
+C<Root.pm> is designed to hold application-wide logic.
+
+=item *
+
+At the end of a given user request, Catalyst will call the most specific 
+C<end> method that's appropriate.  For example, if the controller for a 
+request has an C<end> method defined, it will be called.  However, if 
+the controller does not define a controller-specific C<end> method, the 
+"global" C<end> method in C<Root.pm> will be called.
+
+=item *
+
+Because the definition includes an C<ActionClass> attribute, the
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
+will be executed B<after> any code inside the definition of C<sub end>
+is run.  See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
+for more information on C<ActionClass>.
+
+=item *
+
+Because C<sub end> is empty, this effectively just runs the default 
+logic in C<RenderView>.  However, you can easily extend the 
+C<RenderView> logic by adding your own code inside the empty method body 
+(C<{}>) created by the Catalyst Helpers when we first ran the 
+C<catalyst.pl> to initialize our application.  See 
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more 
+detailed information on how to extended C<RenderView> in C<sub end>.
+
+=back
+
+
+=head2 Using The Default Template Name
+
+By default, C<Catalyst::View::TT> will look for a template that uses the 
+same name as your controller action, allowing you to save the step of 
+manually specifying the template name in each action.  For example, this 
+would allow us to remove the 
+C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our 
+C<list> action in the Books controller.  Open 
+C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
+to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
+has changed):
+
+    =head2 list
+    
+    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
+    
+    =cut
+    
+    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('MyAppDB::Books')->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<Catalyst::View::TT> defaults to looking for a template with no 
+extension.  In our case, we need to override this to look for an 
+extension of C<.tt2>.  Open C<lib/MyApp/View/TT.pm> and add the 
+C<TEMPLATE_EXTENSION> definition as follows:
+
+    __PACKAGE__->config({
+        CATALYST_VAR => 'Catalyst',
+        INCLUDE_PATH => [
+            MyApp->path_to( 'root', 'src' ),
+            MyApp->path_to( 'root', 'lib' )
+        ],
+        PRE_PROCESS  => 'config/main',
+        WRAPPER      => 'site/wrapper',
+        ERROR        => 'error.tt2',
+        TIMER        => 0,
+        TEMPLATE_EXTENSION => '.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.
+
+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
+the C<$c-E<gt>detach> mechanisms (these are discussed in Part 2 and 
+Part 9 of the Tutorial).
+
+
+=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';
+
+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.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
+

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Testing.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Testing.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/Testing.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Testing - Catalyst Tutorial - Part 7: Testing
+Catalyst::Manual::Tutorial::Testing - Catalyst Tutorial - Part 8: Testing
 
 
 =head1 OVERVIEW
 
-This is B<Part 7 of 9> for the Catalyst tutorial.
+This is B<Part 8 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,34 +21,39 @@
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
 =item 7
 
-B<Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+B<Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
 
+
 =head1 DESCRIPTION
 
 You may have noticed that the Catalyst Helper scripts automatically
@@ -71,23 +76,32 @@
 
     $ prove --lib lib t
 
-The redirection used by the Authentication plugins will cause the
-default C<t/01app.t> to fail.  You can fix this by changing the line in
-C<t/01app.t> that read:
+There will be a lot of output because we have the C<-Debug> flag enabled 
+in C<lib/MyApp.pm> (see the C<CATALYST_DEBUG=0> tip below for a quick 
+and easy way to reduce the clutter). Look for lines like this for 
+errors:
 
+    #   Failed test 'Request should succeed'
+    #   in t/controller_Books.t at line 8.
+    # Looks like you failed 1 test of 3.
+
+The redirection used by the Authentication plugins will cause several 
+failures in the default tests.  You can fix this by making the following
+changes:
+
+1) Change the line in C<t/01app.t> that read:
+
     ok( request('/')->is_success, 'Request should succeed' );
 
 to:
 
     ok( request('/login')->is_success, 'Request should succeed' );
 
-So that a redirect is not necessary.  Also, the C<t/controller_Books.t>
-and C<t/controller_Logout.t> default test cases will fail because of the
-authorization.  You can delete these two files to prevent false error
-messages:
+2) Change the C<request('/logout')-E<gt>is_success> to 
+C<request('/logout')-E<gt>is_redirect> in C<t/controller_Logout.t>.
 
-    $ rm t/controller_Books.t
-    $ rm t/controller_Logout.t
+3) Change the C<request('/books')-E<gt>is_success> to 
+C<request('/books')-E<gt>is_redirect> in C<t/controller_Books.t>.
 
 As you can see in the C<prove> command line above, the C<--lib> option
 is used to set the location of the Catalyst C<lib> directory.  With this
@@ -115,6 +129,7 @@
 
     $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib -v t
 
+
 =head1 RUNNING A SINGLE TEST
 
 You can also run a single script by appending its name to the C<prove>
@@ -122,11 +137,12 @@
 
     $ CATALYST_DEBUG=0 prove --lib lib t/01app.t
 
-Note that you can also run tests directly from Perl without C<prove>.
+Also note that you can also run tests directly from Perl without C<prove>.
 For example:
 
     $ CATALYST_DEBUG=0 perl -Ilib t/01app.t
 
+
 =head1 ADDING YOUR OWN TEST SCRIPT
 
 Although the Catalyst helper scripts provide a basic level of checks
@@ -317,13 +333,9 @@
 
     my $dsn = $ENV{MYAPP_DSN} ||= 'dbi:SQLite:myapp.db';
     __PACKAGE__->config(
-        schema_class => 'MyAppDB',
+        schema_class => 'MyApp::Schema::MyAppDB',
         connect_info => [
             $dsn,
-            '',
-            '',
-            { AutoCommit => 1 },
-    
         ],
     );
 

Modified: trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod
===================================================================
--- trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod	2008-05-22 15:48:07 UTC (rev 7771)
+++ trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod	2008-05-22 17:35:28 UTC (rev 7772)
@@ -16,39 +16,43 @@
 
 =over 4
 
-=item *
+=item 1
 
 L<Introduction|Catalyst::Manual::Tutorial::Intro>
 
-=item * 
+=item 2
 
 L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
 
-=item * 
+=item 3
 
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
+
+=item 4
+
 L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
-=item * 
+=item 5
 
 L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
-=item * 
+=item 6
 
 L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
-=item * 
+=item 7
 
 L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
-=item *
+=item 8
 
 L<Testing|Catalyst::Manual::Tutorial::Testing>
 
-=item * 
+=item 9
 
 L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
 
-=item * 
+=item 10
 
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
@@ -60,6 +64,7 @@
 
 =head1 Detailed Table of Contents
 
+
 =head2 L<Part 1: Introduction|Catalyst::Manual::Tutorial::Intro>
 
 =over 4
@@ -93,33 +98,39 @@
 
 =item *
 
-CREATE A SQLITE DATABASE
+HELLO WORLD
 
+=over 4
+
 =item *
 
-EDIT THE LIST OF CATALYST PLUGINS
+The Simplest Way
 
 =item *
 
-DATABASE ACCESS WITH DBIx::Class
+Hello, World! Using a View and a Template
 
+=back
 
-=over 4
-
 =item *
 
-Create a DBIC Schema File
+CREATE A SIMPLE CONTROLLER AND AN ACTION
 
-=item *
+=back
 
-Create the DBIC ``Result Source'' Files
 
+=head2 L<Part 3: More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
+
+
+=over 4
+
 =item *
 
-Use Catalyst::Model::DBIC::Schema to Load the Model Class
+CREATE A NEW APPLICATION
 
-=back
+=item *
 
+EDIT THE LIST OF CATALYST PLUGINS
 
 =item *
 
@@ -138,31 +149,83 @@
 
 =item *
 
-Using RenderView for the Default View
+Globally Customize Every View
 
 =item *
 
-Globally Customize Every View
+Create a TT Template Page
 
+=back
+
 =item *
 
-Create a TT Template Page
+CREATE A SQLITE DATABASE
 
+=item *
+
+DATABASE ACCESS WITH DBIx::Class
+
+=over 4
+
+=item *
+
+Create a Dynamic DBIC Model
+
 =back
 
+=item *
 
+RUN THE APPLICATION
+
 =item *
 
+A STATIC DATABASE MODEL WITH DBIx::Class
+
+=over 4
+
+=item *
+
+Create Static DBIC Schema Files
+
+=item *
+
+Updating the Generated DBIC Schema Files
+
+=back
+
+=item *
+
 RUN THE APPLICATION
 
 =item *
 
-USING THE DEFAULT TEMPLATE NAME
+RUNNING THE APPLICATION FROM THE COMMAND LINE
 
+=item *
+
+UPDATING THE VIEW
+
+=over 4
+
+=item *
+
+Using RenderView for the Default View
+
+=item *
+
+Using The Default Template Name
+
+=item *
+
+Return To A Manually-Specified Template
+
 =back
 
-=head2 L<Part 3: Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+=back
 
+
+=head2 L<Part 4: Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+
 =over 4
 
 =item *
@@ -227,12 +290,29 @@
 
 Try the Delete Feature
 
+=item *
+
+Fixing a Dangerous URL
+
+=item *
+
+Try the Delete and Redirect Logic
+
+=item *
+
+Using uri_for to Pass Query Parameters
+
+=item *
+
+Try the Delete and Redirect With Query Param Logic
+
 =back
 
 =back
 
-=head2 L<Part 4: Authentication|Catalyst::Manual::Tutorial::Authentication>
 
+=head2 L<Part 5: Authentication|Catalyst::Manual::Tutorial::Authentication>
+
 =over 4
 
 =item *
@@ -251,10 +331,6 @@
 
 =item *
 
-Create New ``Result Source Objects''
-
-=item *
-
 Sanity-Check Reload of Development Server
 
 =item *
@@ -311,10 +387,27 @@
 
 =back
 
+=item *
+
+USING THE SESSION FOR FLASH
+
+=over 4
+
+=item *
+
+Try Out Flash
+
+=item *
+
+Switch To Flash-To-Stash
+
 =back
 
-=head2 L<Part 5: Authorization|Catalyst::Manual::Tutorial::Authorization>
+=back
 
+
+=head2 L<Part 6: Authorization|Catalyst::Manual::Tutorial::Authorization>
+
 =over 4
 
 =item *
@@ -367,8 +460,9 @@
 
 =back
 
-=head2 L<Part 6: Debugging|Catalyst::Manual::Tutorial::Debugging>
 
+=head2 L<Part 7: Debugging|Catalyst::Manual::Tutorial::Debugging>
+
 =over 4
 
 =item *
@@ -385,8 +479,9 @@
 
 =back
 
-=head2 L<Part 7: Testing|Catalyst::Manual::Tutorial::Testing>
 
+=head2 L<Part 8: Testing|Catalyst::Manual::Tutorial::Testing>
+
 =over 4
 
 =item *
@@ -407,90 +502,24 @@
 
 =back
 
-=head2 L<Part 8: Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
 
-=over 4
+=head2 L<Part 9: Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
 
-=item *
-
-HTML::WIDGET FORM CREATION
-
 =over 4
 
 =item *
 
-Add the HTML::Widget Plugin
+ADVANCED CRUD OPTIONS
 
-=item *
-
-Add a Form Creation Helper Method
-
-=item *
-
-Add Actions to Display and Save the Form
-
-=item *
-
-Update the CSS
-
-=item *
-
-Create a Template Page To Display The Form
-
-=item *
-
-Add Links for Create and Update via HTML::Widget
-
-=item *
-
-Test The <HTML::Widget> Create Form
-
 =back
 
-=item *
 
-HTML::WIDGET VALIDATION AND FILTERING
+=head2 L<Part 10: Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =over 4
 
 =item *
 
-Add Constraints and Filters to the Widget Creation Method
-
-=item *
-
-Rebuild the Form Submission Method to Include Validation
-
-=item *
-
-Try Out the Form
-
-=back
-
-=item *
-
-Enable DBIx::Class::HTMLWidget Support
-
-=over 4
-
-=item *
-
-Add DBIx::Class::HTMLWidget to DBIC Model
-
-=item *
-
-Use populate_from_widget in hw_create_do
-
-=back
-
-=back
-
-=head2 L<Part 9: Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=over 4
-
-=item *
-
 APPENDIX 1: CUT AND PASTE FOR POD-BASED EXAMPLES
 
 =over 4
@@ -557,19 +586,30 @@
 
 Other Catalyst documentation folks like Kieren Diment, Gavin Henry,
 and Jess Robinson (including their work on the original Catalyst
-tutorial).
+tutorial).  
 
 =item *
 
+Kieren Diment for currently maintaining this document on CPAN.
+
+=item *
+
 Everyone on #catalyst and #catalyst-dev.
 
 =item *
 
+Louis Moore (who thanks Marcello Romani and Tom Lanyon) for the
+PostgreSQL content in the Appendix.
+
+=item *
+
 People who have emailed me with corrections and suggestions on the 
 tutorial.  As of the most recent release, this include: Florian Ragwitz, 
 Mauro Andreolini, Jim Howard, Giovanni Gigante, William Moreno,  
 Bryan Roach, Ashley Berlin, David Kamholz, Kevin Old, Henning Sprang,
-Jeremy Jones, David Kurtz, Ingo Wichmann, and Shlomi Fish.
+Jeremy Jones, David Kurtz, Ingo Wichmann, and Shlomi Fish.  I'm sure I
+am missing some names here... apologies for that (please let me know
+if you name should be here).
 
 =back
 




More information about the Catalyst-commits mailing list