Notes from a Newbie Experiment 01: Simple Dynamic Content and Links

Notes from a Newbie document the creation and deployment of yardbirdfanclub.org with Perl Catalyst on shared hosting. They are intended for a Perl Catalyst Newbie who would like to study the creation and deployment of a Perl Catalyst application.

In these notes I begin to explore what it might take to create a blog application.

What Can I Do With A Database?

Using what I learned in Catalyst::Tutorial and other perldocs, I want to learn to design and use a simple database in a Catalyst application of my own design, and deploy it on the Internet.

What Will It Take To Create A Blog With Catalyst And MySQL?

Wondering but not really caring if there are better ways to create blogs with Perl Catalyst, I decide to explore what it might take to create a database and use it to blog.

I ask myself:

  • What do you want your pages to look like?
  • What database details will you need to use and understand?

I worked through Catalyst::Manual::Tutorial.

I farted around with DBIx::Class::Manual but found these the most useful, they explain how to use a database specifically with Catalyst:

  • Catalyst::Manual::Tutorial::03_MoreCatalystBasics
  • Catalyst::Manual::Tutorial::04_BasicCRUD
  • Catalyst::Manual::Tutorial::05_Authentication
  • Catalyst::Manual::Tutorial::06_Authorization
  • Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormHandler

These were especially helpful too:

  • DBIx::Class::Row
  • DBIx::Class::ResultSource
  • DBIx::Class::ResultSet
  • DBIx::Class::Relationship
  • HTML::FormHandler::Manual::Tutorial
  • HTML::FormHandler::Manual::Catalyst

Viewing Perl documentation with a web browser works pretty good, I use Perldoc::Server.

I know very little HTML or CSS, just a little from the Internet and a CSS book I worked through. Same goes for Perl, I studied a couple Perl books and am strictly an entry-level Perl Catalyst Newbie.

With meager skills I set out to create and deploy a meager blog with Perl Catalyst and MySQL, not very original but it's the best I came up with.

blogs.perl.org

I've not used or seen many blogs, but I like the design of blogs.perl.org. I wondered if I might be able to create one similarly?

Simple Dynamic Content and Links

Simple-minded as I am, I ask myself how the blogs.perl.org blog titles are made into links?

Create MySQL Database

What might a blog database table contain?

  • id (primary key)
  • userid (foreign key)
  • title
  • content

You may be wondering about the userid column, what am I using it for?

After doing some experiments, I will create my Yardbird Catalyst application starting with authentication and authorization as explained in:

  • Catalyst::Manual::Tutorial::05_Authentication
  • Catalyst::Manual::Tutorial::06_Authorization

Anticipating not only user and blog tables but a blog_comment table as well, the userid foreign key will give the Yardbird application access to a blog author's name and other personal info via the blog table. The userid foreign key also enables the ability to cascade edit and delete, greatly decreasing coding effort while increasing reliability.

What happens when a member of The YARDBIRD Fan Club no-longer wants to be a member? Will I want to delete the user but keep the user's blog entries and comments? No way, be done with them, but how? This is where the cascade edit/delete feature comes in. When a user is removed I also want that user's blog entries and comments to be deleted too.

What would you rather do, search for and delete each blog entry and comment individually, or have the application delete them automatically for you?

The blog table's foreign key userid provides the means for blog rows to automatically be (cascade) deleted when corresponding user's are deleted.

The blog table's foreign key userid also allows the application to access user table information, such as a blog author's name, through the blog table. This is very important!

I want to keep this example simple so I won't declare userid to be a foreign key yet, but I will do so later.

yardbird00.sql

CREATE TABLE blog (
  id      INT UNSIGNED NOT NULL AUTO_INCREMENT,
  userid  INT UNSIGNED NOT NULL,
  title   TEXT NOT NULL,
  content TEXT NOT NULL,
  PRIMARY KEY (id)
);
INSERT INTO blog (id, userid, title, content) VALUES (1, 1, 'title id: 1 userid: 1', 'content id: 1 userid: 1'); 
INSERT INTO blog (id, userid, title, content) VALUES (2, 1, 'title id: 2 userid: 1', 'content id: 2 userid: 1'); 
INSERT INTO blog (id, userid, title, content) VALUES (3, 1, 'title id: 3 userid: 1', 'content id: 3 userid: 1');

mysql> create database yardbird00;

> mysql -uusername -ppassword
mysql> create database yardbird00;
mysql> quit;
> mysql -uusername -ppassword yardbird00 < yardbird00.sql
> mysql -uusername -ppassword 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| yardbird00         |
+--------------------+
mysql> use yardbird00;
mysql> show tables;
+----------------------+
| Tables_in_yardbird00 |
+----------------------+
| blog                 |
+----------------------+
mysql> describe blog;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| userid  | int(10) unsigned | NO   |     | NULL    |                |
| title   | text             | NO   |     | NULL    |                |
| content | text             | NO   |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+
mysql> select * from blog;
+----+--------+-----------------------+-------------------------+
| id | userid | title                 | content                 |
+----+--------+-----------------------+-------------------------+
|  1 |      1 | title id: 1 userid: 1 | content id: 1 userid: 1 |
|  2 |      1 | title id: 2 userid: 1 | content id: 2 userid: 1 |
|  3 |      1 | title id: 3 userid: 1 | content id: 3 userid: 1 |
+----+--------+-----------------------+-------------------------+
mysql> quit;

Create Catalyst Application

> catalyst.pl Yardbird

Yardbird> perl Makefile.PL

Yardbird> script/yardbird_create.pl view TT TT

Yardbird> script/yardbird_create.pl model DB DBIC::Schema \
Yardbird> Yardbird::Schema create=static dbi:mysql:yardbird00 username password

Yardbird/root/index.tt:

hello world

Yardbird/lib/Yardbird/Controller/Root.pm:

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

  $c->detach($c->view("TT")); 
}

Run the application:

Yardbird> script/yardbird_server.pl -r

The browser gives:

yfc01a.png

Use Database in Catalyst Application

Yardbird/lib/Yardbird/Controller/Root.pm:

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

  my $rs = $c->model('DB::Blog')->search({});

  my $blog = $rs->next;
  $c->stash->{t1} = $blog->title;
  $c->stash->{c1} = $blog->content;

  $blog = $rs->next;
  $c->stash->{t2} = $blog->title;
  $c->stash->{c2} = $blog->content;

  $blog = $rs->next;
  $c->stash->{t3} = $blog->title;
  $c->stash->{c3} = $blog->content;

  $c->detach($c->view("TT")); 
}

Yardbird/root/index.tt:

<h1>Take A Ride</h1>
<p>[% t1 %]</p>
<p>[% c1 %]</p>

<p>[% t2 %]</p>
<p>[% c2 %]</p>

<p>[% t3 %]</p>
<p>[% c3 %]</p>

The browser gives:

yfc01b.png

Make Content and Links Dynamic

Links

Yardbird/lib/Yardbird/Controller/Root.pm:

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

  my $rs = $c->model('DB::Blog')->search({});

  my $blog = $rs->next;
  $c->stash->{t1} = $blog->title;
  $c->stash->{c1} = $blog->content;
  $c->stash->{id1} = $blog->id;

  $blog = $rs->next;
  $c->stash->{t2} = $blog->title;
  $c->stash->{c2} = $blog->content;
  $c->stash->{id2} = $blog->id;

  $blog = $rs->next;
  $c->stash->{t3} = $blog->title;
  $c->stash->{c3} = $blog->content;
  $c->stash->{id3} = $blog->id;

  $c->detach($c->view("TT")); 
}

sub blog :Path('blog') :Args(1) {
  my ( $self, $c, $id ) = @_;

  $c->stash->{id} = $id;
  $c->detach($c->view("TT"));
}

Yardbird/root/index.tt:

<h1>Take A Ride...</h1>
<p><a href="[% c.uri_for_action('/blog', id1) %]">[% t1 %]</a></p>
<p>[% c1 %]</p>

<p><a href="[% c.uri_for_action('/blog', id2) %]">[% t2 %]</a></p>
<p>[% c2 %]</p>

<p><a href="[% c.uri_for_action('/blog', id3) %]">[% t3 %]</a></p>
<p>[% c3 %]</p>

Yardbird/root/blog.tt:

<h1>...On The Wild Side.</h1>
<p>[% id %]</p>

The browser gives:

yfc01c.png

Selecting the first title gives:

yfc01c1.png

Improve Code

Yardbird/lib/Yardbird/Controller/Root.pm:

package Yardbird::Controller::Root;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller' }

__PACKAGE__->config(namespace => '');

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

  $c->stash(blog_entries => [$c->model('DB::Blog')->search({})]);

  $c->detach($c->view("TT")); 
}

sub blog :Path('blog') :Args(1) {
  my ( $self, $c, $id ) = @_;

  $c->stash(blog_entry => $c->model('DB::Blog')->search({id => $id}));

  $c->detach($c->view("TT"));
} 

sub default :Path {
    my ( $self, $c ) = @_;
    $c->response->body( 'Page not found' );
    $c->response->status(404);
}

sub end : ActionClass('RenderView') {}

__PACKAGE__->meta->make_immutable;

1;

Yardbird/root/index.tt:

<h3>Take A Ride...</h3>
[% FOREACH blog_entry IN blog_entries %]
  <p><a href="[% c.uri_for_action('/blog', blog_entry.id) %]">[% blog_entry.title %]</a></p>
  <p>[% blog_entry.content %]</p>
[% END %]

Yardbird/root/blog.tt:

<h3>On The Wild Side.</h3>
<p>blog_entry.id: [% blog_entry.id %]</p>
<p>blog_entry.title: [% blog_entry.title %]</p>
<p>blog_entry.content: [% blog_entry.content %]</p>

The browser gives:

yfc01d.png

Selecting the third title gives:

yfc01d3.png

We have finished the difficult part, it will get much easier now.

Leave a comment

About j0e

user-pic I have experience and am skilled at maintaining old school Perl 5 and am seeking opportunities to use modern Perl.