Background:

What is Catalyst?
Why did you make Catalyst?
What is with the name?
Are there any Future plans?
How much does Catalyst cost?
What is Catalyst's License?
How to get Catalyst
How Catalyst Compares with Rails
What's a good place to start?

Build/Install Issues:

Where do I get Catalyst? And build and install it?
I just updated to a version past X.YYY, how do I update my scripts/*?

General Technical Questions:

Can I make the modules be automatically reloaded on update?
How do I distribute Catalyst applications?
How to set cookies in Catalyst?
What is $c->comp() for?
What is your application class for?
What's the difference between 'auto' and the other builtin actions (default, begin, end)?
How can I get a context object ($c) in my tests?

Errors and Debugging:

How to debug your app:
ERROR: "Couldn't forward to "some_action". Invalid or not loaded."
GOTCHA: Why isn't my css file getting served?
Internet Explorer sometimes fails on redirects when using the standalone server.
GOTCHA: path_info does not behave and arguments are weird in default
How to display the debug screen without adding die() calls

Authentication:

How do I do authentication?

Sessions:

How to persist your objects:

Static Content:

How do I stop Catalyst from serving static files in my app/root directory?:

Performance:

How to increase your Template Toolkit performance

Best Practices:

Sample web server configurations
Cleaning up URLs


Background

What is Catalyst?

Catalyst is a Perl-based framework for developing web-applications. It was inspired by Maypole and Ruby on Rails, and is thus what we like to call a MVC (Model-View-Controller) framework. Some keywords for Catalyst are Flexibility, Simplicity and Speed. The flexibility stems from our Lego architecture, and Catalyst can talk to your favorite libriaries, we have view support for TT, Mason, HTML-Template, Petal and more, and model support for amongst others, DBIx::Class, Class::DBI, Tangram, Plucene and Net::LDAP.

Why did you make Catalyst?

To make web development fun again.

What is with the name?

The name is the result of a highly scientific process, when some early adapters kept shouting out names on irc until we found something that sounded good. :)

What are the future plans?

To rule the universe, what else is there?

How much does Catalyst cost?

Catalyst is Free. That means both Gratis as in beer, and Free as in speech. :)

What license is Catalyst released under?

Catalyst is licensed under the same terms as Perl itself. That means a dual GPL/Artistic License scheme.

How do I get Catalyst?

See section Where do I get Catalyst.

How does Catalyst compare with Ruby on Rails?

For a fairly objective comparison, check out VersusRails

How does Catalyst compare with CGI::Application?

There's an overview on the CGI::Application wiki: CatalystCompared.

What is a good place to start?

In addition to the Catalyst::Manual and Catalyst::Tutorial

pages on CPAN, Andy Grundman's ServerDB

sample application is a simple, typical database-backed web app. Also, Andy has written up an intro to the application(http://www.hybridized.org/catalyst/), and taken together the app and the writeup are a great tutorial.

Other resources on the Catalyst wiki include NecessaryBackgroundKnowledge, BeginnerInfo, FlowChart, and UserIntroductions.

Build and Install Issues

Where do I get Catalyst

There are several ways to obtain Catalyst:

  1. CPAN
  2. Snapshot
  3. SVN
  4. Debian packages
  5. FreeBSD ports
  6. Gentoo Overlay
  7. CatInABox

CPAN

install Task::Catalyst

Snapshot

fetch the latest from http://dev.catalyst.perl.org/snapshots/Catalyst/

SVN

svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst

Windows Active Perl

Go to http://home.ngmedia.net/chansen/catalyst/ppms/ and read the top of the page for information: Catalyst PPM's for ActivePerl? Windows v5.8.x

ppm> repository add Theoryx5 http://theoryx5.uwinnipeg.ca/ppms/

ppm> repository add Catalyst http://home.ngmedia.net/chansen/catalyst/ppms/

ppm> install Catalyst

There's is also a page describing a PPM-based installation of Task::Catalyst (v1.5).

Debian package

Thanks to Krzysztof Krzyżaniak, Florian Ragwitz and others. Catalyst is now part of the official Debian archive pool. Simply apt-get install libcatalyst-perl

Go to pkg-catalyst team page for more information.

FreeBSD ports

Make sure your port tree is up to date and run the following commands as root

# basic install
cd /usr/ports/www/p5-Task-Catalyst && make install clean
# mod_perl support
cd /usr/ports/www/p5-Catalyst-Engine-Apache && make install clean

or if you have sysutils/portupgrade installed:

# basic Catalyst install
portinstall p5-Task-Catalyst
# mod_perl support
portinstall p5-Task-Catalyst-Engine-Apache

Gentoo Overlay

See [Catalyst HOWTO for Gentoo].

CatInABox

CatInABox? is a one-shot gets all amalgamation of a basic Catalyst + dependencies install. It doesn't include everything you would need for a full install, but it does handle the stickier dependency issues.

I just updated to a version past X.YYY, how do I update my scripts/*

catalyst.pl -nonew -scripts My::App

To refresh your scripts directory with any new features. You will want to go back and add any changes that you have made by hand to these scripts.

General Technical Questions

Can I auto reload modules on update?

Answer 1: Catalyst 5.49_03 and higher include a -r switch to yourapp_server.pl which will reload modules while debugging (NOTE: you don't want to run this as your production server though!).

Answer 2: You can try using one of the Apache::Reload equivalents, but that will only reload as far as Apache is concerned--Catalyst will not be aware of your changes, so it will not change (e.g.) its dispatch rules to dispatch to your new actions.

Whoever writes the solution to this will be the recipient of fame, fortune, and more wealth and power than they can imagine. Or at least a hearty "thank you" from the community.

Read some further information and possible workarounds to this problem at: ReStart?

How can I distribute Catalyst Apps?

The default (and recommended) packaging method is to use Module::Install.

To pack up an application, use 'make manifest' and then 'make dist' to create a redistributable tar of the application directory.

In your application base directory:

  1. edit prereqs in Makefile.PL
  2. perl Makefile.PL
  3. make manifest (edit MANIFEST.SKIP and run make manifest again if you'd like to exclude certain file patterns)
  4. make dist
  5. copy YourApp?-version.tar.gz to the destination system, unpack and run it..

You can also use the PAR support *FIXME*

How do I set cookies in Catalyst?

$c->res->cookies->{cookie_name} = { 
    value => 'cookie value',
    expires => '+1y'
};

...and then let Catalyst handle the rest.

Valid options are:

  • value
  • expires
  • domain
  • path
  • secure

To access the cookie data on a future request, you can call

my $value = $c->req->cookie('cookie_name')->value;

For more information, see the documentation for CGI::Cookie.

What is $c->comp() for?

$c->comp() allows you to check which controllers, models and views have been loaded into your Catalyst app.

You can always get access to a component by calling $c->comp('!MyApp::MyComponent?'). But I don't know why you'd need to do this, rather than just calling !MyApp::MyComponent?->my_method directly.

The difference is that !MyApp::MyComponent is the class whereas $c->comp('!MyApp::MyComponent?') is the object (instance).

What is your application class for?

The thing to know about your app is that it's your context object ($c). Or rather, the "context" object is a Catalyst::Engine object blessed into your application class. What this does is it gives $c all your config info, and also lets you add application specific stuff (ie. custom methods) to $c at will. Just beware that $c already inherits tons of methods, so it would be wise to use a namespacing prefix for all your own methods.

What's the difference between 'auto' and the other builtin actions (default, begin, end)?

The difference is that every auto acts like it has a SUPER call at the start, so you automatically call all autos up the inheritance chain. So when you want something that won't be overridden by subclasses, put it in auto. A typical use is authentication.

How can I get a context object ($c) in my tests?

You can do this as follows:

  my $c = MyApp->prepare

Errors and Debugging

How to debug your app?

Catalyst is very nice about dumping all request/response/stash state when it dies. Some people put

	die if $c->req->params->{die};

in their 'end' action to enable dying on command for this reason (but make sure you put it before your template gets processed).

Another technique, useful when you want to follow the flow through a routine, is to do this:

    sub foo : <Path|Local|etc> {
        my ($self, $c) = @_;


        push @{$c->stash->{checkpoints}}, 'Entering foo';
        

        if ( some_condition() ) {
            push @{$c->stash->{checkpoints}}, 'In foo: "some_condition" true';
            ...do stuff...
        } else {
            push @{$c->stash->{checkpoints}}, 'In foo: "some_condition" false';
        }

        ...etc...
    }

Then, make sure your script dies at some point, and you can look at the stash information to see exactly where control flow went.

Another nice debug feature is the server output, if you run it using the built-in server (./script/myapp_server.pl).

To investigate further use the perl debugger as shown in this [DebugSample].

What is ERROR: "couldn't forward to "some_action". Invalid or not loaded"

ERROR: "Couldn't forward to "some_action". Invalid or not loaded."

One reason for this error is that the action path may be missing an initial slash. I discovered this because $c->req->action strips off the initial slash. If you want to grab that action and reuse it later, you'll need to add the slash back on.

Gotcha: Why isn't my CSS file getting served?

You may first wish to try using the Static::Simple plugin instead of the Static plugin. It will handle css files perfectly. If you still wish to use the Static plugin, read the rest of this section.

The Static plugin uses the File::!MimeInfo::Magic module to work out what to serve each file as. I guess it doesn't support css files. You can work around this with the following code:

         if ($c->req->path =~ /css$/i) {
                 $c->serve_static( "text/css" );
         } else {
                 $c->serve_static;
         }
  • This does not seem to be an issue in Catalyst 5.23 and Catalyst::Plugin::Static 0.07. css files are served as "text/css" without problem in my application.
    • The issue here is with the version of the shared-mime-info package you have installed. Older versions didn't support CSS properly. For more info, see the "Serving Static Content" section of the Cookbook. --andyg

Internet Explorer sometimes fails on redirects when using the standalone server

It's been observed that IE will sometimes display the so-called "friendly" error page when trying to do a redirect that is the result of a POST request. We aren't quite sure of the reason this occurs, but we do have a workaround. If you run the standalone server in keep-alive mode with the -k switch, the error will go away.

Could this be related to the problem described here and the fix described here on Microsoft's support site?

GOTCHA: path_info does not behave and arguments are weird in default

When first doing your own path (called path_info in CGI) you will start to notice that the entire path is returned - often called the Absolute Path. That is the path of the URL after the host and port number.

In Apache and other CGI implementations - path_info is set to the path after the current module - for example if you write a CGI and setup ScriptAlias? as /mytest - then you go to the URL http://www.test.blah/mytest/xxx/yyy.html - then your path_info will = "/xxx/yyy.html"

In Catalyst - path_info will equal "/mytest/xxx/yyy.html" - but do not fear - you can easily get access to path_info using the ->arguments method of Catalyst::Request. Note ->arguments returns a reference to an array containing the data - so don't forget you may need to rejoin it with "/" between each entry.

The real GOTCHA though is "sub default : Private" - The default method should behave exactly the same, but it completely doesn't. ->arguments in default method will always contain all of the path, and there is no real way around that. This (in my opinion) is the incorrect behaviour - we are told that it is because the objects inherit default.

The solution though is fairly simple. Use a Local, Regex, Global or Path instead. A nice simple version is using "sub yourmethod : Path {}" - which will match the path of the current context.

In conclusion: Use "join("/", @{$c->req->arguments})" where you would normally use "path_info", and always use them in a dispatched method, rather than "sub default".

How to display the debug screen without adding die() calls

If you use Catalyst::Plugin::DefaultEnd, adding ?dump_info=1 to the end of the URL will force your Catalyst app to die on that page and print the debug screen.

This can be very handy when you're unsure as to why something you think ought to be present in your page isn't.

Authentication

How do I do authentication?

Use the Catalyst::Plugin::Authentication and Catalyst::Plugin::Authorization framework. This also includes support for Access Control Lists (ACLs) and Roles.

Overview: http://catalyst.perl.org/calendar/2005/14

Sessions

Use the Catalyst::Plugin::Session framework.

Overview: http://catalyst.perl.org/calendar/2005/15

How do I make my objects persist?

Catalyst is designed to work with Object Relational Mapping (ORM) tools like DBIx::Class (DBIC) and Class::DBI (CDBI). There are some extensions such as DBIx::Class::Schema::Loader which provide similar functionality to Ruby on Rail's ActiveRecord -- inspecting your db and automagically doing the right thing. Note that if you do want to use these features (by, say, subclassing Catalyst::Model::DBIx::Schema), you also need to subclass Catalyst::Base.

There are a variety of approaches here, depending on how much control you want over the way your objects get persisted. Since I needed a lot of control over my classes, and found it confusing to sort out how to do that with all the magic flying around, I opted for the ultra-simple approach of using DBIC the usual way. !MyApp::M::DBI subclasses DBIx::Class, and all my model classes subclass !MyApp::M::DBI. And that's it. My model classes do all the usual DBIC stuff and don't know that they exist in a catalyst environment. Works fine. [Someone please tell me if this is a terrible idea.]

  • This is perfectly fine, and is the same thing I do in my more recent applications. Using standalone models also allows you to use them in non-Catalyst cron jobs, for example, which I tend to do often. --andyg
  • I have a similar project, but attempting to subclass the existing models from Catalyst::Base caused problems due to method name clashes - no big issue, just don't sublass from Catalyst::Base then! BUT what are the implications of not subclassing from Catalyst::Base? What functionality am I going to lose, and does it mean I may run into problems at a later point? --rich

Static Content

How do I stop Catalyst from serving static content from my app/root/ directory?

As of Catalyst 5.5, the Static::Simple plugin ships with Catalyst and is enabled by default. If you would like to have your web server serve static content directly remove the Static::Simple line from your "use Catalyst" line.

An alternative solution to this problem involves configuring Apache and copying the static directory to apache's document root:

# Copy static content to document root.
# Note: clients will be accessing these files as:
# http://localhost/myapp/static/<whatever>
# ( let's assume the document root is /var/www/htdocs )
mkdir /var/www/htdocs/myapp
cp -a root/static /var/www/htdocs/myapp/static

# By default, /myapp locations are handled by the Catalyst application:
PerlModule MyApp
<Location /myapp>
    SetHandler perl-script
    PerlResponseHandler MyApp
</Location>
# Let Apache handle /myapp/static locations:
<Location /myapp/static>
    SetHandler default-handler
</Location>

This solution is not as simple as the previous one, but works for older versions of Catalyst.

Performance

How do I increase my TT performance?

You can increase the performance of your templates by using a template cache for pre-compiled templates and the XS version of the TT stash. Simply use the following code in your view. If you don't have the XS Stash module, you can rebuild Template Toolkit and choose to build it when it asks you.

Warning: Do not use the XS Stash if you need to access tied hashes in your templates.

package MyApp::V::TT;

use strict;
use base 'Catalyst::View::TT';
use Template::Stash::XS;

__PACKAGE__->config(
    COMPILE_DIR => "/tmp/template_cache",
    STASH => Template::Stash::XS->new,
);

1;

Note: You might want to specify COMPILE_DIR as "/tmp/template_cache_$<", which adds the user id to the directory name if your application may be run as different users (i.e. from Apache and from developer login accounts). Template Toolkit creates cache files with permissions 0600, so if a common cache directory is used, a cache file generated by developer while debugging could prevent a production application running as the web user from rendering a template!

To avoid permission issues you can use a 'local' tmp dir:

package MyApp::V::TT;

use strict;
use base 'Catalyst::View::TT';
use Template::Stash::XS;
use Path::Class qw(dir);    # portable way of generating a path

__PACKAGE__->config(
    COMPILE_DIR => dir( MyApp->config->{home}, 'tmp') ,
    STASH => Template::Stash::XS->new,
);

1;

(A similar approach can be used for other things as well, for example session storage).

See also:

Doesn't TT use these Options by default?

  • If you selected "use XS Stash by default for all templates" when you installed TT, it will use the XS Stash. File caching is not enabled unless you specify a COMPILE_DIR yourself.

Best Practices

Sample Web Server Configurations

chansen has been kind enough to provide a set of web server configurations that you can build your environment from. They're located at http://home.ngmedia.net/chansen/catalyst/conf/. He includes samples for Apache 1.3, 2.0, and lighttpd utilizing mod_perl, speedycgi, fastcgi, and "standard" cgi.

Also, a walk-through on using Catalyst on a DreamHost server.

The main Catalyst-Engine-Apache docs:

and lastly an article on Installing lighttpd and FastCGI for Catalyst.

Cleaning up URLs

At the end of something like user registration, you'd like to redirect to home but with a nice message. If you use $c->res->redirect, your stash goes away. If you use forward, your url is ugly. ANSWER NEEDED

Catalyst::Plugin::Session adds a method called $c->flash. The flash is similar to a session, but it persists only from one redirect until the next, and thus can be used for exactly this purpose. Actually it persists from when it is written, to the next time it is read, and thus can survive over multiple redirects, if not touched.

I usually just do something like this:

[%# homepage.tt %]
<p>Welcome to MySite!</p>
[% IF message %][% message %][% END %]
<p>Some more stuff would go here!</p>

Then in the controller class:

sub default : Private {
  my($self,$c) = @_;
  $c->res->redirect('index');
}
sub index : Local {
  my($self,$c) = @_;
  $c->stash(template => 'homepage.tt');
}
sub welcome : Local {
  my($self,$c) = @_;
  my $name = $c->session->first_name; # session data from the registration
  $c->stash(template => 'homepage.tt', message => "Thanks for registering, $name!");
}

Then you can just redirect to /welcome instead of /index when you want to give them the welcome message, by populating the stash after the redirect rather than before, you avoid the problem of losing the stash across a redirect.

How do I get relative URIs in my templates with c->uri_for()?

uri_for() returns URI objects so you can use its methods, like path(). E.g.–

Absolute URI:  [% c.uri_for("/something", "more") %]
Just the path: [% c.uri_for("/something", "more").path %] # drops query_string and such!