/best practices

Catalyst best practices

Follow the Catalyst diet: thin controller, fat model.

Decouple as much as possible. If you have to fire up your web application in order to test database insertion, that's wrong. Build the model so that you can use Perl one liners to manipulate data through it. For example, with MojoMojo, you can do:

perl -Ilib -MMojoMojo -le' MojoMojo->model("DBIC::Person")->find({login=>"admin"})->update({pass=>"wonky"}) '

Models: The Definitive Guide

See Models Definitive Guide

Use the recommended modules and plugins

See recommended plugins.

$c->stash Sets and Gets

Set a Single Value

Two ways to store things in $c->stash:

  1. $c->stash(key => value)
  2. $c->stash->{key} = $value

NOTE: Bruce Lee prefers the first method in general for putting things in the stash. The second approach may occasionally be useful in hairy (long value) situations (e.g. where you want a specific part of a complex data structure).

Stash Multiple Values

The first approach above leads naturally into setting multiple values in one $c->stash call. For example,

    sex      => 'female', 
    look     => 'good',
    weather  => 'hot',
    medicine => 'herb',
    swim     => 'now',       

Get Your Stash

my $medicine = $c->stash->{medicine};

Don't Use BindLex

The lead author says don't use it, so don't. It was one of those things that looked good at the time, but wasn't.

Using Catalyst::Controller::action_for combined with $c->uri_for

There are two forms of $c->uri_for():

  1. Arguments: ( $action, \@captures?, @args?, \%query_values? )

    NOTE: $controller->action_for returns a catalyst action object. This is the more flexible because of object introspection advantages (see #catalyst for an explanation).

    Example: $c->uri_for( $c->controller('YourController')->action_for('action_method') );

  2. Arguments: ( $path, @args?, \%query_values? )

    In this case, the $path is not an object, thus it can't introspect nor have a dynamic URI.

Using Catalyst::Controller::uri_for_action()

Starting Catalyst 5.8.1 there is a new short and reliable way to generate dynamic URIs.

  1. Arguments: ( $path, \@captures?, @args?, \%query_values? )

    The first argument is a path to the action method which is converted into an action object and handed over to uri_for.

    Example: $c->uri_for_action('/yourcontroller/action_method')

  2. Arguments: ( $action, \@captures?, @args?, \%query_values? )

    In this case all arguments are directory passed to uri_for


Translation strings

Assume that the translated strings will return back information "as-is" without any markup. Therefore, you will need to escape characters based on where the text is being used:


For TT, pass through the html filter:

<p>[% c.loc("Some text that might have < or > in it") | html %]</p>

Javascript strings

Pass through escape_js_string filter. You can use single or double quotes for the string assignment.

< script >
var string = '[% c.loc("May have single quotes or \ in it") | escape_js %]';
< /script >

(Note: we've put spaces around the < and > to avoid actually defining script tags)

escape_js can be defined in MyApp::View::TT with:

use Template::Filters;  # Need to use, so that we can have access to $Template::Filters::FILTERS
$Template::Filters::FILTERS->{escape_js} = \&escape_js_string;

sub escape_js_string {
    my $s = shift;
    $s =~ s/(\\|'|"|\/)/\\$1/g;
    return $s;

HTML elements with javascript snippets

Pass through the escape_js_string filter, then the html filter:

< select onclick=" alert('[% c.loc("May have all sorts of things in it") | escape_js | html %]') ">

(Extra space added to stop interpretation of select tag)

It is best to use double quotes for the attribute value and then single quotes for the javascript strings.


Preventing Cross site scripting

It is quite important you filter any input that may come from the user or an untrusted source. This can be done by filtering output in templates (i.e [% DATA | html %] ) A good example of a place to be sure to do this is in the default error page (error.tt2) for TTSite. By default, the error message is not html encoded.