Go from L<Module::Name|Module::Name> to L<Module::Name>
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 04_BasicCRUD.pod
index 8506531..c2135f7 100644 (file)
@@ -70,13 +70,13 @@ Although this chapter of the tutorial will show you how to build CRUD
 functionality yourself, another option is to use a "CRUD builder" type 
 of tool to automate the process.  You get less control, but it can be 
 quick and easy.  For example, see 
-L<Catalyst::Plugin::AutoCRUD|Catalyst::Plugin::AutoCRUD>, 
-L<CatalystX::CRUD|CatalystX::CRUD>, and 
-L<CatalystX::CRUD::YUI|CatalystX::CRUD::YUI>.
+L<Catalyst::Plugin::AutoCRUD>, 
+L<CatalystX::CRUD>, and 
+L<CatalystX::CRUD::YUI>.
 
 You can check out the source code for this example from the Catalyst
 Subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+L<Catalyst::Manual::Tutorial::01_Intro>.
 
 
 =head1 FORMLESS SUBMISSION
@@ -116,11 +116,9 @@ Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
     
-        # Assign the Book object to the stash for display in the view
-        $c->stash->{book} = $book;
-    
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
+        # Assign the Book object to the stash for display and set template
+        $c->stash(book     => $book,
+                  template => 'books/create_done.tt2');
     }
 
 Notice that Catalyst takes "extra slash-separated information" from the
@@ -170,7 +168,7 @@ Edit C<root/src/books/create_done.tt2> and then enter:
 The TT C<USE> directive allows access to a variety of plugin modules
 (TT plugins, that is, not Catalyst plugins) to add extra functionality
 to the base TT capabilities.  Here, the plugin allows
-L<Data::Dumper|Data::Dumper> "pretty printing" of objects and
+L<Data::Dumper> "pretty printing" of objects and
 variables.  Other than that, the rest of the code should be familiar
 from the examples in Chapter 3.
 
@@ -336,7 +334,7 @@ chapter of the tutorial and explore slightly more advanced capabilities
 with the base method and delete feature below.  But Chained dispatch
 is capable of far more.  For additional information, see
 L<Catalyst::Manual::Intro/Action types>,
-L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>,
+L<Catalyst::DispatchType::Chained>,
 and the 2006 Advent calendar entry on the subject:
 L<http://www.catalystframework.org/calendar/2006/10>.
 
@@ -359,9 +357,8 @@ to the following:
     | /books/url_create                   | /books/url_create                    |
     '-------------------------------------+--------------------------------------'
 
-Now start the development server with our basic chained method in
-place and the startup debug output should change to something along
-the lines of the following:
+When the development server restarts, the debug output should change 
+to something along the lines of the following:
 
     [debug] Loaded Path actions:
     .-------------------------------------+--------------------------------------.
@@ -380,7 +377,7 @@ the lines of the following:
     | /books/url_create/*/*/*             | /books/url_create                    |
     '-------------------------------------+--------------------------------------'
 
-C<url_create> has disappeared form the "Loaded Path actions" section
+C<url_create> has disappeared from the "Loaded Path actions" section
 but it now shows up under the newly created "Loaded Chained actions"
 section.  And the "/*/*/*" portion clearly shows our requirement for
 three arguments.
@@ -413,7 +410,7 @@ method:
         my ($self, $c) = @_;
     
         # Store the ResultSet in stash so it's available for other methods
-        $c->stash->{resultset} = $c->model('DB::Book');
+        $c->stash(resultset => $c->model('DB::Book'));
     
         # Print a message to the debug log
         $c->log->debug('*** INSIDE BASE METHOD ***');
@@ -495,7 +492,7 @@ Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
         my ($self, $c) = @_;
     
         # Set the TT template to use
-        $c->stash->{template} = 'books/form_create.tt2';
+        $c->stash(template => 'books/form_create.tt2');
     }
 
 This action simply invokes a view containing a form to create a book.
@@ -549,15 +546,13 @@ save the form information to the database:
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
     
-        # Store new model object in stash
-        $c->stash->{book} = $book;
-    
         # Avoid Data::Dumper issue mentioned earlier
         # You can probably omit this
         $Data::Dumper::Useperl = 1;
     
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
+        # Store new model object in stash and set template
+        $c->stash(book     => $book,
+                  template => 'books/create_done.tt2');
     }
 
 
@@ -766,7 +761,7 @@ equivalent.
 
 =head2 Try the Delete Feature
 
-One you save the Books controller, the server should automatically restart.
+Once you save the Books controller, the server should automatically restart.
 The C<delete> method should now appear in the "Loaded Chained actions" section
 of the startup debug output:
 
@@ -891,7 +886,7 @@ query parameter:
     ...
     <div id="content">
         [%# Status and error messages %]
-        <span class="message">[% status_msg || c.request.params.status_msg %]</span>
+        <span class="message">[% status_msg || c.request.params.status_msg | html %]</span>
         <span class="error">[% error_msg %]</span>
         [%# This is where TT will stick all of your template's contents. -%]
         [% content %]
@@ -909,7 +904,10 @@ C<E<lt>span class="message"E<gt>> line.
 Point your browser to L<http://localhost:3000/books/list> (you should 
 now be able to safely hit "refresh" in your browser). Then delete the 
 remaining copy of "TCPIP_Illustrated_Vol-2". The green "Book deleted" 
-status message should return. 
+status message should return.  But notice that you can now hit the
+"Reload" button in your browser and it just redisplays the book
+list (and it correctly shows it without the "Book deleted" message
+on redisplay).
 
 B<NOTE:> Another popular method for maintaining server-side
 information across a redirect is to use the C<flash> technique we
@@ -940,8 +938,8 @@ Let's add two columns to our existing C<books> table to track when
 each book was added and when each book is updated:
 
     $ sqlite3 myapp.db
-    sqlite> ALTER TABLE book ADD created INTEGER;
-    sqlite> ALTER TABLE book ADD updated INTEGER;
+    sqlite> ALTER TABLE book ADD created TIMESTAMP;
+    sqlite> ALTER TABLE book ADD updated TIMESTAMP;
     sqlite> UPDATE book SET created = DATETIME('NOW'), updated = DATETIME('NOW');
     sqlite> SELECT * FROM book;
     1|CCSP SNRS Exam Certification Guide|5|2010-02-16 04:15:45|2010-02-16 04:15:45
@@ -972,7 +970,7 @@ with the new fields:
      exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
 
 Notice that we modified our use of the helper slightly: we told
-it to include the L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp>
+it to include the L<DBIx::Class::TimeStamp>
 in the C<load_components> line of the Result Classes.
 
 If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you should 
@@ -992,9 +990,9 @@ B<above> the C<1;> on the last line):
     #
     __PACKAGE__->add_columns(
         "created",
-        { data_type => 'datetime', set_on_create => 1 },
+        { data_type => 'timestamp', set_on_create => 1 },
         "updated",
-        { data_type => 'datetime', set_on_create => 1, set_on_update => 1 },
+        { data_type => 'timestamp', set_on_create => 1, set_on_update => 1 },
     );
 
 This will override the definition for these fields that Schema::Loader 
@@ -1020,6 +1018,7 @@ time entered for it (see the last line in the listing below):
     5|Designing with Web Standards|5|2010-02-16 04:15:45|2010-02-16 04:15:45
     9|TCP/IP Illustrated, Vol 3|5|2010-02-16 04:15:45|2010-02-16 04:15:45
     10|TCPIP_Illustrated_Vol-2|5|2010-02-16 04:18:42|2010-02-16 04:18:42
+    sqlite> .q
 
 Notice in the debug log that the SQL DBIC generated has changed to
 incorporate the datetime logic:
@@ -1086,13 +1085,13 @@ Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
-        $c->stash->{books} = [$c->model('DB::Book')
-                                ->created_after(DateTime->now->subtract(minutes => $mins))];
+        $c->stash(books => [$c->model('DB::Book')
+                                ->created_after(DateTime->now->subtract(minutes => $mins))]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 Now try different values for the "minutes" argument (the final number 
@@ -1103,7 +1102,7 @@ fifteen minutes:
     http://localhost:3000/books/list_recent/15
 
 Depending on how recently you added books, you might want to
-try a higher or lower value.
+try a higher or lower value for the minutes.
 
 
 =head2 Chaining ResultSets
@@ -1136,15 +1135,15 @@ C<lib/MyApp/Controller/Books.pm> and add the following method:
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
         # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
+        $c->stash(books => [$c->model('DB::Book')
                                 ->created_after(DateTime->now->subtract(minutes => $mins))
                                 ->search({title => {'like', '%TCP%'}})
-                             ];
+                            ]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 To try this out, enter the following URL into your browser:
@@ -1203,15 +1202,15 @@ shown here -- the rest of the method should be the same):
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
         # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
+        $c->stash(books => [$c->model('DB::Book')
                                 ->created_after(DateTime->now->subtract(minutes => $mins))
                                 ->title_like('TCP')
-                             ];
+                            ]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 Try out the C<list_recent_tcp> and C<list_recent> URLs as we did above. 
@@ -1233,7 +1232,7 @@ C<lib/MyApp/Schema/Result/Author.pm> and add the following method (as
 always, it must be above the closing "C<1;>"):
 
     #
-    # Helper methods
+    # Row-level helper methods
     #
     sub full_name {
         my ($self) = @_;
@@ -1269,7 +1268,7 @@ And, because the concatenation logic was encapsulated inside our
 Result Class, it keeps the code inside our TT template nice and clean
 (remember, we want the templates to be as close to pure HTML markup as
 possible). Obviously, this capability becomes even more useful as you
-use to to remove even more complicated row-specific logic from your
+use it to remove even more complicated row-specific logic from your
 templates!
 
 
@@ -1362,7 +1361,7 @@ huge comments to clue people in to the gist of our code. The view code
 is now self-documenting and readable enough that you could probably get 
 by with no comments at all. All of the "complex" work is being done in 
 our Result Class methods (and, because we have broken the code into 
-nice, modular chucks, the Result Class code is hardly something you 
+nice, modular chunks, the Result Class code is hardly something you 
 would call complex).
 
 As we saw in this section, always strive to keep your view AND 
@@ -1381,9 +1380,13 @@ down.
 
 Kennedy Clark, C<hkclark@gmail.com>
 
-Please report any errors, issues or suggestions to the author.  The
-most recent version of the Catalyst Tutorial can be found at
+Feel free to contact the author for any errors or suggestions, but the
+best way to report issues is via the CPAN RT Bug system at
+<https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
+
+The most recent version of the Catalyst Tutorial can be found at
 L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
 
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+Copyright 2006-2010, Kennedy Clark, under the
+Creative Commons Attribution Share-Alike License Version 3.0
 (L<http://creativecommons.org/licenses/by-sa/3.0/us/>).