Catalyst Model #1: Random quotes

Published · Monday, 13 July 2009 (Updated · 7 March 2010)

This is not meant as a serious model recommended for production but to show you how gorgeously simple a useful model can be. This site uses something entirely similar but based out of external flat files instead of __DATA__ based, as it were. That way it can be configured like any good Catalyst piece and quote files can be swapped and edited without touching code. Note, I didn’t try it but suspect this model would not work under modperl.

Create your model with the helper

./script/ model RandomQuote
 exists "/Users/jinx/depot/sites/MyApp/script/../lib/MyApp/Model"
 exists "/Users/jinx/depot/sites/MyApp/script/../t"
created "/Users/jinx/depot/sites/MyApp/script/../lib/MyApp/Model/"
created "/Users/jinx/depot/sites/MyApp/script/../t/model_RandomQuote.t"

Open her up and see how 6 lines of code can run an entire model

emacs lib/MyApp/Model/
package MyApp::Model::RandomQuote;
use strict;
use warnings;
use parent 'Catalyst::Model';

# The do block ensures localized $/ can't escape its scope.
my @Quotes = do { local $/ = "\n\n"; <DATA> } ;

sub get_one : method {
    $Quotes[rand @Quotes];

sub get_all : method {
    wantarray ? @Quotes : [ @Quotes ];


A house can have integrity, just like a person, and just as seldom.

One can’t love man without hating most of the creatures who pretend to
bear his name.

There is a stage of worship which makes the worshipper himself an
object of reverence.

You know how people long to be eternal. But they die with every day
that passes. When you meet them, they’re not what you met last. In any
given hour, they kill some part of themselves. They change, they deny,
they contradict—and they call it growth. At the end there’s nothing
left, nothing unreversed or unbetrayed; as if there had never been an
entity, only a succession of adjectives fading in and out on an
unformed mass.

Show me your achievement—and the knowledge will give me courage for mine.

She could not have reached this white serenity except as the sum of
all the colors, of all the violence she had known.

…the person who loves everybody and feels at home everywhere is the
true hater of mankind. He expects nothing of men, so no form of
depravity can outrage him.

To say “I love you” one must know first how to say the “I.”

I can accept anything, except what seems to be the easiest for most
people: the half-way, the almost, the just-about, the in-between.

Put in a controller with two methods to consume the model

./script/ controller RandomQuote
emacs lib/MyApp/Controller/
 exists "/Users/jinx/MyApp/script/../lib/MyApp/Controller"
 exists "/Users/jinx/MyApp/script/../t"
created "/Users/jinx/MyApp/script/../lib/MyApp/Controller/"
created "/Users/jinx/MyApp/script/../t/controller_RandomQuote.t"
package MyApp::Controller::RandomQuote;
use strict;
use warnings;
use parent 'Catalyst::Controller';

sub quote :Local Args(0) {
    my ( $self, $c ) = @_;
    my $quote = $c->model("RandomQuote")->get_one;
    $c->response->content_type("text/html; charset=utf-8");

use CGI qw( ol li );
sub show_all :Local Args(0) {
    my ( $self, $c ) = @_;
    my @quotes = $c->model("RandomQuote")->get_all;
    $c->response->content_type("text/html; charset=utf-8");
    $c->response->body( ol( li( \@quotes ) ) );


Fire it up

./script/ -d -r -p 3000
[debug] Debug messages enabled
[debug] Statistics enabled
[debug] Loaded plugins:
| Catalyst::Plugin::ConfigLoader  0.24                                       |
| Catalyst::Plugin::Static::Simple  0.21                                     |
| Catalyst::Plugin::Unicode  0.91                                            |

[debug] Loaded dispatcher "Catalyst::Dispatcher"
[debug] Loaded engine "Catalyst::Engine::HTTP"
[debug] Found home "/Users/jinx/depot/sites/MyApp"
[debug] Loaded components:
| Class                                                           | Type     |
| MyApp::Controller::RandomQuote                                  | instance |
| MyApp::Controller::Root                                         | instance |
| MyApp::Model::RandomQuote                                       | instance |

[debug] Loaded Private actions:
| Private              | Class                                | Method       |
| /default             | MyApp::Controller::Root              | default      |
| /index               | MyApp::Controller::Root              | index        |
| /randomquote/quote   | MyApp::Controller::RandomQuote       | quote        |

[debug] Loaded Path actions:
| Path                                | Private                              |
| /                                   | /index                               |
| /                                   | /default                             |
| /randomquote/quote                  | /randomquote/quote                   |
| /randomquote/show_all               | /randomquote/show_all                |

[info] 10 Example Catalyst Models, v0.01 powered by Catalyst 5.80007
You can connect to your server at http://jasper.local:3000

When you’re to this point, http://localhost:3000/randomquote/quote and http://localhost:3000/randomquote/show_all should be good to go. Give’em a try.

Note that we left out an index/base method so http://localhost:3000/randomquote will get a 404 not found. This is what I would call a bad practice. I’ve seen it live on various sites more often lately.

The following addition will fix it for you by making the quote method synonymous with the index. Also might not be the way to go but you just learned something, right? So it’s not just academic… Uh, I mean, it’s exactly academic.

sub index :Path Args(0) {
    my ( $self, $c ) = @_;

Tomorrow we’ll tackle Catalyst Model #2: Moon phase data.

do block style slurp added per suggestion from Larry Leszczynski.

digg stumbleupon reddit Fark Technorati Faves

Catalyst Model #2: Moon phase data »
« 10 Catalyst models in 10 days1 »