This part of the tutorial builds on the fairly primitive application
created in Part 2 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
+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
IMPORTANT: Does not work yet. Will be completed for final version.
-
=head1 FORMLESS SUBMISSION
Our initial attempt at object creation will utilize the "URL arguments"
=head2 url_create
- Create a book with the supplied title, rating and author
+ Create a book with the supplied title, rating, and author
=cut
sub url_create : Local {
- # In addition to self & context, get the title, rating & author_id args
- # from the URL. Note that Catalyst automatically puts extra information
- # after the "/<controller_name>/<action_name/" into @_
+ # In addition to self & context, get the title, rating, &
+ # author_id args from the URL. Note that Catalyst automatically
+ # puts extra information after the "/<controller_name>/<action_name/"
+ # into @_
my ($self, $c, $title, $rating, $author_id) = @_;
# 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({
- title => $title,
- rating => $rating
+ title => $title,
+ rating => $rating
});
# Add a record to the join table for this book, mapping to
[% # optional, but prevents "massive indenting" of deeply nested objects -%]
[% USE Dumper(Indent=1) -%]
- [% # Set the page title -%]
+ [% # Set the page title. META can 'go back' and set values in templates -%]
+ [% # that have been processed 'before' this template (here it's for -%]
+ [% # root/lib/site/html and root/lib/site/header). Note that META on -%]
+ [% # simple strings (e.g., no variable interpolation). -%]
[% META title = 'Book Created' %]
[% # Output information about the record that was added. Note use -%]
- [% # of 'first' to only list the first author (if > 1 author). -%]
- <p>Added book '[% book.title %]' by '[% book.authors.first.last_name %]'
+ [% # of 'first' to only list the first author (if > 1 author). TT -%]
+ [% # v2.15 has an issue that requires -%]
+ [% # 'book.authors.list.first.value.last_name' vs. the shorter -%]
+ [% # 'book.authors.first.last_name' in prior versions. -%]
+ <p>Added book '[% book.title %]'
+ by '[% book.authors.list.first.value.last_name %]'
with a rating of [% book.rating %].</p>
[% # Provide a link back to the list page -%]
[% # 'uri_for()' builds a full URI; e.g., 'http://localhost:3000/books/list' -%]
<p><a href="[% Catalyst.uri_for('/books/list') %]">Return to list</a></p>
- [% # Try out the TT Dumper -%]
+ [% # Try out the TT Dumper (for development only!) -%]
<pre>
Dump of the 'book' variable:
[% Dumper.dump(book) %]
</pre>
-The TT C<USE> directive allows access to a variety of plugin modules (we
-are talking TT plugins here, 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 variables.
-Other than that, the rest of the code should be familiar from the
-examples in Part 2.
+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>
+"pretty printing" of objects and variables. Other than that, the rest
+of the code should be familiar from the examples in Part 2.
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
context object in TT templates from the usual C<c> to C<Catalyst>.
-
=head2 Try the C<url_create> Feature
If the application is still running from before, use C<Ctrl-C> to kill
-it. Then restart the server:
+it. Then restart the server:
$ script/myapp_server.pl
B<TIP>: You can use C<script/myapp_server.pl -r> to have the development
server auto-detect changed files and reload itself (if your browser acts
odd, you should also try throwing in a C<-k>). If you make changes to
-just the TT templates, you do not need to reload the development server
+the TT templates only, you do not need to reload the development server
(only changes to "compiled code" such as Controller and Model C<.pm>
files require a reload).
C</books/list> page).
-
=head1 MANUALLY BUILDING A CREATE FORM
Although the C<url_create> action in the previous step does begin to
$c->stash->{template} = 'books/form_create.tt2';
}
-This action merely invokes a view containing a book creation form.
-
+This action simply invokes a view containing a book creation form.
=head2 Add a Template for the Form
Open C<root/src/books/form_create.tt2> in your editor and enter:
- [% META title = 'Book Create' -%]
+ [% META title = 'Manual Form Book Create' -%]
<form method="post" action="[% Catalyst.uri_for('form_create_do') %]">
<table>
Note that we have specified the target of the form data as
C<form_create_do>, the method created in the section that follows.
-
=head2 Add Method to Process Form Values and Update Database
Edit C<lib/MyApp/Controller/Books.pm> and add the following method to
# Store new model object in stash
$c->stash->{book} = $book;
- # Avoid Data::Dumper issue mention earlier
+ # Avoid Data::Dumper issue mentioned earlier
# You can probably omit this
$Data::Dumper::Useperl = 1;
=head2 Test Out The Form
-If the application is still running from before, use C<Ctrl-C> to kill it. Then restart the server:
+If the application is still running from before, use C<Ctrl-C> to kill
+it. Then restart the server:
$ script/myapp_server.pl
"Return to list" to view the full list of books.
B<Note:> Having the user enter the primary key ID for the author is
-obviously a bit crude; we will address this concern with a drop-down
-list in Part 8.
-
-
+obviously crude; we will address this concern with a drop-down list in
+Part 8.
=head1 A SIMPLE DELETE FEATURE
<td>[% book.title %]</td>
<td>[% book.rating %]</td>
<td>
- [% # Print author count in parens. 'book.authors' uses the 'many_to_many' -%]
- [% # relationship to retrieve all of the authors of a book. 'size' is a -%]
- [% # TT VMethod to get the number of elements in a list. -%]
- ([% book.authors.size %])
- [% # Use an alternate form of a FOREACH loop to display authors. -%]
- [% # _ below is the TT string concatenation operator. -%]
- [% author.last_name _' ' FOREACH author = book.authors %]
- [% # Note: if many_to_many relationship not used in Authors.pm, you could -%]
- [% # have used the following to 'walk' through the 'join table objects' -%]
- [% # bk_author.author.last_name _' ' FOREACH bk_author = book.book_authors %]
+ [% # 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 we are making a bogus assignment to -%]
+ [% # the 'xx' vbl to avoid printing the size of the list after each push. -%]
+ [% tt_authors = [ ];
+ xx = tt_authors.push(author.last_name) FOREACH author = book.authors %]
+ [% # Now use a TT 'virtual method' to display the author count -%]
+ ([% tt_authors.size %])
+ [% # Use another TT virtual method to join the names with comma separators -%]
+ [% tt_authors.join(', ') %]
</td>
<td>
[% # Add a link to delete a book %]
right side of the table with a C<Delete> "button" (for simplicity, links
will be used instead of full HTML buttons).
-
=head2 Add a Delete Action to the Controller
Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
following method:
- =head2 Delete
+ =head2 delete
Delete a book
Copyright 2006, Kennedy Clark, under Creative Commons License
(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
-Version: .94
-