3 Catalyst::Manual::Tutorial - Getting started with Catalyst
7 This document aims to get you up and running with Catalyst.
11 The first step is to install Catalyst, and the simplest way to do this
12 is to install the Catalyst bundle from CPAN:
14 $ perl -MCPAN -e 'install Task::Catalyst'
16 This will retrieve Catalyst and a number of useful extensions and
17 install them for you. This process might not be totally painless
18 though, and you might want to look at CatInABox at
19 L<http://use.perl.org/~jk2addict/journal/28071>, especially if you are
20 on a system that lacks a compiler.
23 =head2 The very basics - Setting up the skeleton application.
25 Catalyst includes a helper script, C<catalyst.pl>, that will set up a
26 skeleton application for you:
28 $ catalyst.pl tutorial
31 created "tutorial/script"
33 created "tutorial/script/tutorial_create.pl"
35 This creates the directory structure, populated with skeleton
38 =head2 Testing out the skeleton application
40 You can test out your new application by running the server script that
44 $ script/tutorial_server.pl
46 [debug] Debug messages enabled
47 [debug] Loaded plugins:
48 .------------------------------------------------------------------------------.
49 | Catalyst::Plugin::Static::Simple |
50 '------------------------------------------------------------------------------'
51 [debug] Loaded dispatcher "Catalyst::Dispatcher"
52 [debug] Loaded engine "Catalyst::Engine::HTTP"
53 [debug] Found home "/home/users/me/tutorial"
54 [debug] Loaded Private actions:
55 .--------------------------------------+---------------------------------------.
57 +--------------------------------------+---------------------------------------+
58 | /default | tutorial |
59 '--------------------------------------+---------------------------------------'
61 [...] [catalyst] [info] tutorial powered by Catalyst 5.67
62 You can connect to your server at http://localhost:3000
64 (Note that each line logged by Catalyst begins with a timestamp, which has
65 been replaced here with "C<...>" so that the text fits onto the lines.)
67 The server is now waiting for you to make requests of it. Try using
68 telnet to manually make a simple GET request of the server (when
69 telnet responds with "Escape character is '^]'.", type "GET / HTTP/1.0"
70 and hit return twice):
72 $ telnet localhost 3000
74 Connected to localhost.
75 Escape character is '^]'.
79 Date: Mon, 07 Nov 2005 14:57:39 GMT
81 Content-Type: text/html; charset=utf-8
86 Connection closed by foreign host.
89 You can see the full welcome message by visiting
90 http://localhost:3000/ with your browser.
92 More trace messages will appear in the original terminal window:
94 [debug] *** Request 1 (0.063/s) [2148]
95 [debug] Arguments are ""
96 [debug] "GET" request for "/" from localhost
97 [info] Request took 0.046883s (21.330/s)
98 .------------------------------------------------------------------+-----------.
100 +------------------------------------------------------------------+-----------+
101 | /default | 0.000000s |
102 '------------------------------------------------------------------+-----------'
104 The server will continue running until you interrupt it.
106 The application can also be tested from the command line using the generated
107 helper script, C<script/tutorial_test.pl>.
109 =head2 Getting started
111 So you picked Catalyst. Good choice. We assume you have installed it as
112 well. For this tutorial you will also need the following modules:
114 L<Catalyst::Plugin::Session>
116 L<Catalyst::Plugin::Session::Store::File>
118 L<Catalyst::Plugin::Session::State::Cookie>
120 L<Catalyst::Plugin::Authentication>
122 L<Catalyst::Plugin::Authentication::Store::Minimal>
124 L<Catalyst::Plugin::Authentication::::Minimal>
126 L<Catalyst::Plugin::Authentication::Credential::Password>
128 L<Catalyst::Plugin::Authorization::Roles>
134 If you have not already done this following the example above, then to get
135 started all you need to do is type:
140 Poor choice of application name - searching for "tutorial" in the docs
141 also results in discussion of the tutorial process, which is probably
142 not what the reader wants.
146 This should create a directory called F<tutorial> and fill it with the
147 default (standard) Catalyst installation. Change to this directory
148 because we will be running all further commands from inside the
149 F<tutorial> directory.
151 If you now run the built-in mini-server with:
153 script/tutorial_server.pl
155 it will show some standard debug messages in the console screen
156 (more about those in a minute), and then inform you that you can now
157 connect to the test server on port 3000. Point your browser at
158 http://localhost:3000/ to see the built-in Catalyst welcome screen.
160 The other important thing B<catalyst.pl> did was create your root
161 controller. This file is a standard Perl module like all the other
162 controllers that you might add to your application. It lives in the
163 F<lib/> directory, and will have the same name as you supplied to the
164 command above. In our case it is F<tutorial.pm>. Alongside this file is
165 a directory of the same name, which is the top level namespace for the
166 entire application. Thus every other module we create will be
167 "tutorial::something".
169 The root controller is used to load plugins, to configure the
170 application and its plugins, and for generic private actions. We will
171 explain more about those later.
175 The simplest way to debug your Catalyst application is to run it using
176 the built-in mini-server as described in L<Getting started>.
178 If you want to output any debugging information to the console, then
179 call C<< $c->log->debug() >>, passing it a string to output. For data
180 structures, C<use> L<Data::Dump> qw/dump/; and call
181 C<< $c->log->debug(dump($structure)) >>
183 =head2 Model/View/Controller
185 The recommended method for code organization in a Catalyst application
186 is known as the "Model View Controller" design pattern (also referred to
187 "MVC". See L<http://en.wikipedia.org/wiki/Model-view-controller>).
189 The point of the MVC pattern is to separate the dependencies of parts of
190 the application from each other, and give them standard
191 interfaces. Following this theory of organization should give your code
192 all the benefits of modularity. The main benefits are interchangeability
193 of parts and reusability of code.
195 Thus you could replace your flat-file data storage with a relational
196 database, or your MySQL database with an Oracle database, and not have
197 to change any of your Controller or View logic. Or you could later
198 decide to output information from your application as RSS instead of
199 HTML just by adding a new View module.
203 Models deal with the storage of data. For a complex website, you may
204 need multiple data sources, each having its own model class that
205 provides an abstracted interface to it. In this tutorial we are going to
206 be using a simple database.
210 Views are used to display information to the user. In a web framework,
211 the View is generally used to output HTML to the browser. As mentioned
212 previously, Views can also be used to output RSS or any other kind of
213 data. One easy way to do this with Catalyst is to use a templating
214 system such as L<Template Toolkit|Template>. If outputting HTML is all
215 you are going to do, then you will probably only need one View.
219 A controller is responsible for responding to user choices, and thus
220 controls what the application does. Since this is a web framework,
221 Catalyst controllers are frequently used to react directly to URLs
222 requested by the user. This tutorial will describe the simplest way of
223 using controllers, where each path or part of a path is assigned its own
224 action (or subroutine). More complex controlling mechanisms will be
225 mentioned briefly, and can be read about in detail elsewhere in the
231 Now let's write our first bit of application code. First, we would like
232 our application to greet our users. We'll assume for now that our users
233 will be sent to the I<users/greet> URL. To create a controller that
234 serves the I<users> namespace, we run the following command in our
235 F<tutorial> directory:
237 script/tutorial_create.pl controller Users
239 This will create a Users.pm in F<lib/tutorial/Controller>. Open this
240 file in an editor and take a look. You will notice there is some
241 commented-out code which we will ignore for now. To make something
242 happen when our URL is visited, we will write a "greet" action which
248 my $name = $c->req->param('name');
249 $c->log->debug("Got name: $name\n");
251 if ($c->req->method eq 'POST') {
253 $c->stash->{message} = 'Please fill in a name!';
256 $c->stash->{message} = "Hello $name!";
259 $c->stash->{template} = 'greet.tt';
262 Whew! So, what does all this do? Let's take it one step at a time. The
263 subroutine declaration gives the action a name. To the right of the name
264 there is an attribute type that looks like this:
268 That defines which URIs will translate to this action. "Local" matches
273 The URI matched by "Local" is composed from the namespace minus the
274 tutorial::controller portion, that is common to all controllers,
275 and the action name itself. Because it is a URI, we use forward slashes
276 instead of double colons. So, in summary, when a user requests:
278 http://localhost:3000/users/greet
280 the "greet" action defined above in the Users controller will be executed.
282 The second line retrieves the parameters Catalyst gives us when it calls
283 our method. The first is the instance of our Users class, and the second
284 is commonly called the "context", held in C<$context>, or abbreviated to
285 C<$c>. From now on, whenever we are talking about the context object,
286 it will be represented as C<$c> in the code.
288 The context is the magical object containing any information you need from
289 catalyst, or want to send to it, and is passed from action to action.
290 You will see it used frequently in Catalyst applications, and a list of all
291 its methods is available in the L<Catalyst> POD.
293 On the third line we use the ->param method of the context's request object
294 to retrieve one of the query parameters, just like in L<CGI>.
296 On the fourth, we make a debug output of this object on the server console,
297 or the error log if running under CGI or mod_perl.
299 Next, if we have a post request, we check if the name field contains
300 anything (or is "true"). If it isn't, we assign an error message to a
301 "message" field in the stash. The stash is a special hash of the context
302 object, which allows us to pass data on to other methods we call later,
303 typically in the View.
305 If the username did contain a value, then we just set our message to
306 greet the user by name.
308 Finally, we set the special "template" variable in the stash to the name
309 of the template we want our View to use to display this page.
313 OK, so reacting and checking the users data is all fine, but how do we
314 actually display the page/form in the first place, and our results? In
315 this tutorial, we'll use Template Toolkit for our viewing. To create our
316 TT-based view, just run the following command:
318 script/tutorial_create.pl view TToolkit TT
320 Notice that this time we not only gave it the type of module we wanted
321 to create (a view), and a name, but also a third argument, "TT". This is
322 a Catalyst helper module, which will make a standard Template Toolkit
323 module for you. And that's all you need to do there.
325 To use the view, the easiest way is to set up a standard "end" action.
326 This is a special private action which will not be matched to a path
327 like our "greet" action, but instead will be called after all other
328 processing is done. Only one end action will be called in any request
329 cycle. If there is one in a controller, it will be preferred over one in
330 the application module, and so on.
332 Since we're writing a simple application, just add an end action like
333 this to F<tutorial.pm>:
337 $c->forward('tutorial::View::TToolkit') unless $c->res->body();
340 The first line declares the end sub, and marks it as a Private action.
341 (This is the second and last attribute type we'll be using in this
342 tutorial.) The second line collects our standard parameters as shown in
343 the controller's greet action.
345 The third line directs Catalyst to pass processing on to our TToolkit
346 view. The forward method, when just passed a class name, calls
347 C<process> on that class. The standard TT view's C<process> method
348 renders the template named in the template variable in the stash, using
349 all the other variables in the stash as values to fill it in.
351 NB: This is such a common way to end your processing that there is a
352 plugin which does it for you: L<Catalyst::Plugin::DefaultEnd>.
354 Template Toolkit also has access to the entire context object via the
355 special variable "c". For example, using C<[% c.config.name %]> in our
356 template will output "tutorial", our project name.
358 All that remains is to create a simple template called "greet.tt",
359 containing a form with a text field called "name" like below.
361 <html><head><title> [% c.config.name %]</head><body>
363 <form action="[% c.req.uri %]" method="post">
364 <input type="text" name="name"/>
365 <input type="submit" value="Submit" name="submit"/>
369 In the example above, we use C<[% c.req.uri %]>, since we're posting to
370 ourself. If we post to another action, we commonly use the uri_for
373 [% c.uri_for('/users/greet')%]
375 Place this file in the F<root> directory. By default, templates are
376 searched for here, but we can change that, which brings us to...
380 As previously mentioned, the configuration of modules, plugins, and so
381 on is done in the main application file. This is especially true for
382 bits which need to be done before an instance of them is created, for
383 example Template Toolkit.
385 The TT View looks for its templates in the F<root> directory by default.
386 Since this is also the directory that static files go in, we'd rather
387 have a separate F<templates> directory. To do this, change the config
388 call in F<tutorial.pm> like this:
390 __PACKAGE__->config( name => 'tutorial',
391 'View::TToolkit' => {
392 'INCLUDE_PATH' => __PACKAGE__->path_to('templates')
396 And move the F<greet.tt> file from F<root> to the F<templates> directory
399 Now we can run our application again by killing (B<ctrl-c>) and restarting
400 B<script/tutorial_server.pl>. Try connecting to
401 I<localhost:3000/users/greet> with a browser and see what happens. What
402 happens if you try to visit I<localhost:3000/users> ?
404 =head2 Users and Authenticating
406 One of the many reasons to write dynamic websites instead of just using
407 static HTML is to allow us to produce different content for different
408 users, as well as restricting access to pages (which we could do with
409 just Apache's htpasswd system).
411 In this tutorial, we will just be using basic authentication. When
412 writing a real application, you'll want to use a database or other
413 secure store to contain your user data.
415 To add authentication, all we need to do is add the
416 L<Catalyst::Plugin::Authentication> module to our main application
417 file. Then we need to pick a storage method (one of the
418 L<Catalyst::Plugin::Authentication::Store> modules), and a method of
419 verifying the user's credentials (one of the
420 L<Catalyst::Plugin::Authentication::Credential> modules). Edit
421 F<tutorial.pm> to look like this:
423 use Catalyst qw/-Debug Static::Simple Authentication
424 Authentication::Store::Minimal
425 Authentication::Credential::Password/;
427 To configure, add some users to the config call. For example:
429 authentication => { 'users' =>
431 { 'password' => 'fred1234',
436 Generally, setting up configuration data for plugins is done based on
437 the type of plugin. Check the documentation of the plugin for exact
438 details; in this example we should look in
439 L<Catalyst::Plugin::Authentication::Store::Minimal>.
441 Since our user data is in the config, we can update it at runtime, and
442 thus add users dynamically. (Of course, to keep them permanently we'd
443 need to save our data to disk and read it back into the config on
446 To allow creation of new users we'll add a C<create> action to our Users
451 my ($username, $passwd1, $passwd2) = map { $c->req->param($_)}
452 ('username', 'password', 'passwordverify');
454 if($username && $passwd1 && $passwd2) {
455 if($c->config->{authentication}{users}{$username}) {
456 $c->stash->{message} = 'Sorry, that user already exists';
457 $c->stash->{username} = $username;
459 elsif($passwd1 eq $passwd2) {
460 $c->config->{authentication}->{users}->{$username} =
461 {password => $passwd1};
462 $c->stash->{message} = 'User created!';
465 $c->stash->{username} = $username;
466 $c->stash->{message} = 'Passwords do not match!';
469 $c->stash->{template} = 'usercreate.tt';
472 All this is doing is checking that all the appropriate fields are
473 filled, and that the password fields contain the same data, and then
474 adding the user to the config hash. All the checks produce a message
475 which can be displayed to the user via the View.
477 The usercreate.tt template looks like this:
479 <html><head><title>[% c.config.name %]</title></head><body>
480 <h1>Create a new user</h1>
481 <h2>Current users are:</h2>
483 [% FOREACH key = c.config.authentication.users.keys %]
487 <p> [% message %] </p>
488 <form action="/users/create" method="post">
489 <p>User Name: <input type="text" name="username"/></p>
490 <p>Password: <input type="password" name="password"/></p>
491 <p>Confirm Password: <input type="password" name="passwordverify"/></p>
492 <p><input type="submit" name="submit" value="submit"></p>
496 In order for our users to be able to login, we need a C<login> action
497 which we put in the Users controller:
501 $c->stash->{template} = 'userlogin.tt';
503 $c->stash->{message} = 'Please login.';
506 $c->stash->{message} = "Welcome " . $c->user->id;
511 And the userlogin.tt template:
513 <html><head><title>[% c.config.name %]</title></head><body>
514 <p> [% message %] </p>
515 <form name='login' action='/users/login' method='post'>
516 <p>Username: <input type='text' name='user' /></p>
517 <p>Password: <input type='password' name='password' /></p>
518 <p><input type="submit" /></form>
522 Very simple. Since Credential::Password's "login" call extracts the
523 username/password data from the query itself (assuming we use a standard
524 name for our form fields), we don't have to do anything but call it.
526 To keep the user logged in, all we need to do is add the Session modules
527 to our collection, and the Auth modules will automatically use them:
529 use Catalyst qw/-Debug Static::Simple Authentication
530 Authentication::Store::Minimal
531 Authentication::Credential::Password
532 Session Session::Store::File Session::State::Cookie/;
538 As an exercise for the reader, do the following:
540 Change C<users/greet> and C<greet.tt> so that the welcome message greets
543 Enforce user logging in by adding an C<auto> action in tutorial.pm (see
544 the L<Catalyst> documentation to find out about the C<auto> action).
548 Authentication is about verifying users, and authorization is about
549 allowing them to do things. Catalyst currently has two Authorization
550 modules, Roles and ACL. The Roles module allows you to define groups
551 which you can assign your users to, and then allow access to areas of
552 your website to the groups. The ACL module lets you do more fine grained
553 access/restriction by allowing of denying access however you like. (It
554 also supports Roles as done by the roles module.) This example uses
555 L<Catalyst::Plugin::Authorization::Roles>. To use this add
556 "Authorization::Roles" into the "use Catalyst" statement in tutorial.pm.
558 Adding Roles via the Minimal store we are already using is quite simple,
559 we just add a roles key to each user, defining the names of the roles
562 authentication => { 'users' =>
564 { 'password' => 'fred1234',
570 We need an interface for our admins to administer the roles, i.e. assign
571 the users to groups. To restrict access to certain actions, we just need
572 to call C<< $c->check_user_roles() >> in each action. So we can
573 make a restricted I<http://localhost:3000/users/groups> page like this:
577 if($c->check_user_roles('admin')) {
578 # Now we can do things only an admin will see
579 if (my $params = $c->req->params) {
580 my $users = $c->config->{authentication}{users};
581 foreach my $u (keys %$params) {
582 $users->{$u}{roles} = $params->{$u} if($users->{$u});
584 $c->stash->{message} = 'Updated user roles!';
587 $c->stash->{users} = $c->config->{authentication};
589 $c->stash->{template} = 'usersgroups.tt';
592 $c->stash->{message} = 'Admins Only!';
593 $c->stash->{template} = 'error.tt';
597 What we are doing here is checking whether the logged-in user (used by
598 default in the C<check_user_roles> method) is a member of the admin
599 group. If it is, then we display the usergroups template, and update
600 the users hash as required. Otherwise, we just show the user an error
603 For this simple example, the usersgroups.tt and error.tt templates could
606 <html><head><title>[% c.config.name %]</title></head><body>
608 <p>[% c.stash.users %]</p>
611 And that's all there is to it.
614 So it's not clear what the groups action is doing - and with the
615 current template, nothing happens. Running through the sample code,
616 it's clear what's happening (which is very little), but the purpose,
617 and how to display data is not clear.
621 So that you can test this out properly without having to go to the
622 trouble of deleting browser cookies manually, we will add a logout
623 action in the Users controller:
627 $c->stash->{message} = "You have successfully logged out";
632 =head2 Data Storage (Modelling)
634 Whether we want our users to be able to contribute to our website, or
635 just create it from changeable data, we need to store the data
636 somewhere. Generally this is done using a database, but models can also
637 use other data sources, for example another website, or an RSS feed.
639 If you have or want a database, there are still choices to be
640 made. There are several modules for accessing databases using an
641 object-oriented wrapper. The best known are probably L<DBIx::Class> and
642 L<Class::DBI>. Catalyst supports making models using either of these.
644 For a simple example, we will allow our users to store their favorite
645 greeting in our database. Create a table called "greetings" in a
646 database, that contains a "user" field and a "greeting" field. The
647 simplest way to create a model of your database is to use these helper
648 modules, for example with L<DBIx::Class>:
650 script/tutorial_create.pl model UserData DBIC dbi:SQLite:/path/to/mydb.db
652 This will cause the DBIx::Class Loader to inspect your database, and create a
653 module in the Model::UserData namespace for each table in your database.
655 Now we need a form for our users to enter/edit their personal greetings
656 in, so we'll make a I<http://localhost:3000/users/editgreeting> page:
658 sub editgreeting : Local {
660 if($c->req->params->{greeting}) {
661 if(!$c->user_exists) {
662 $c->stash->{message} = "You're not logged in!";
665 my $grtable = $c->model('UserData::Greetings');
666 my $record = $grtable->find_or_create(user => $c->user->id);
667 $record->greeting($c->req->params->{greeting});
669 $c->stash->{message} = 'Greeting updated';
672 $c->stash->{template} = 'usersgreeting.tt';
675 Using C<< $c->user_exists >> from the Authentication plugin, this checks
676 whether the user is logged in already. If they are, and they have
677 entered a new greeting, we use DBIx::Class' C<find_or_create> method to
678 fetch or create a new record in the greetings table for the user. Once
679 we have the record, we change the value of the greeting field, and call
680 C<update> to store the new value in the database.
682 =head2 Engines (Apache and FastCGI)
684 Now that we have the basics together, we can try running our application on a
685 "real" server instead of just using the test server that Catalyst comes
686 with. L<Catalyst::Engine> is the module used to implement various types of
687 servers to run it on. The current popular ones are Apache and FastCGI.
691 Apache needs to be configured: we need to tell it to load your
692 application. You can either use Catalyst for your entire website, or
693 subsections. Use the Location directive to choose a path to run your
697 SetHandler perl-script
698 PerlResponseHandler tutorial
701 You will need to install the perl modules of your application into one
702 of perl's library directories, as listed by B<perl -V>, so that Apache
703 can find them. Alternatively you can use the C<PerlSwitches> directive
704 to tell Apache where to look:
706 PerlSwitches -I/path/to/tutorial/
708 These instructions are for using Apache2 and mod_perl 2.0. If you are
709 using mod_perl 1.3 or 1.99, please refer to either
710 L<Catalyst::Engine::Apache::MP13> or L<Catalyst::Engine::Apache2::MP19>
711 for details of the slightly different ways to do it.
713 If you wish to ensure that Apache pre-loads your application, use the
714 PerlModule directive. This means that there will be less of a delay when
715 your application is accessed.
721 These instructions apply to the use of C<mod_fastcgi> under Apache
722 (either 1 or 2 series).
724 There are 3 ways to attach a program to a URL with C<mod_fastcgi>;
725 we'll examine all of them, and explain how to avoid having the
726 C<tutorial_fastcgi.pl> substring in the user-visible URLs.
728 In all of these examples, we assume that the C<DocumentRoot> is
729 C</var>, that our app is called C<tutorial> and is kept in C</usr>, that
730 you want the users to access the app either from the root of the
731 server-uri-space, or from C</theapp>. We also assume that the general
732 FastCGI settings (C<FastCgiIpcDir>, loading the module) are already
733 correct (they don't depend on Catalyst or your application layout).
735 =head4 static application
737 In this setup, you tell C<mod_fastcgi> that a particular I<file> is to
738 be run as a FastCGI handler. Put this somewhere in Apache's
741 FastCgiServer /usr/apps/tutorial/script/tutorial_fastcgi.pl
742 Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
744 If you want your app under C</theapp>, change the C<Alias> line to:
746 Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
748 Note the detail of the trailing C</ >: this is a general rule of the
749 C<Alias> directive, both sides must end with C</ >, or both must not;
750 you can't have one with C</ > and the other without, or strange things
753 =head4 dynamic application
755 In this setup, you tell C<mod_fastcgi> that certain files are to be
756 treated as FastCGI handlers, in the same way you have to tell
757 C<mod_cgi>. Put this in the configuration:
759 FastCgiConfig -autoUpdate
761 <Directory /usr/apps/tutorial/script>
764 SetHandler fastcgi-script
768 Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
770 Again, if you want your app under C</theapp>, change the C<Alias> line to:
772 Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
774 =head4 external server
776 In this setup, the application is started separately from Apache, and
777 communicates via a socket with C<mod_fastcgi>. This can be useful if
778 you need to have a particular environment for your application (maybe
779 different between applications), or you want to run them on different
780 machines, or under different users for security reasons.
782 If you want to use a UNIX socket (on the filesystem), put this in
783 Apache's configuration:
785 FastCgiExternalServer /tmp/somewhere -socket /tmp/tutorial-socket
786 Alias / /tmp/somewhere/
788 Note that C</tmp> should I<not> exist: it's just a name to connect the
791 Again, if you want your app under C</theapp>, change the C<Alias> line
794 Alias /theapp /tmp/somewhere
796 Then start your Catalyst application:
798 $ cd /usr/apps/tutorial
799 $ ./script/tutorial_fastcgi -l /tmp/tutorial-socket
801 If you want to use a TCP socket, simply change the C</tmp> to a
802 C<host:port> pair, both in Apache's configuration and on the command
803 line of your application.
807 Upgrading your application to newer Catalyst versions is quite
808 simple. After installing the new Catalyst package, just run:
812 One level above your application directory. This will update the scripts
813 directory only, and leave the rest of your app alone. If you wish to
814 make use of other parts of Catalyst that have been updated, leave off
815 the B<-scripts> argument, this will cause .new files to appear, for each
816 module that has either been updated, or is different to the original
817 because you have changed it. To find out what these changes are, type:
819 diff tutorial/lib/tutorial/View/TT.pm tutorial/lib/tutorial/View/TT.pm.new
821 for each of the changed files. (This is a Unix command; Windows users
822 will need to find some equivalent.) Copy any changes you need into your
823 original file, then remove the .new files. (This makes life less
824 complicated when the next upgrade comes around.)
828 Jess Robinson, C<jrobinson@cpan.org>
829 Andrew Ford, C<A.Ford@ford-mason.co.uk>
830 Marcus Ramberg, C<mramberg@cpan.org>
831 Kieren Diment, C<kd@totaldatasolution.com>
832 Gavin Henry, C<ghenry@cpan.org>
834 Please send comments, corrections and suggestions for improvements to
835 jrobinson@cpan.org, ghenry@cpan.org
839 Finish DBIC examples with templates and tested code. Make /users/groups
840 do something "useful".
842 Many other things....
846 This program is free software, you can redistribute it and/or modify
847 it under the same terms as Perl itself.