Press Releases with Mason

To learn more about building dynamic web sites, Mr. Lerner presents an application for reading the news using Mason and MySQL.
Adding Categories

The first step toward making our news system work is to allow users to create new categories. Each news story in our simple system will be placed in precisely one category, much as each story in a newspaper is printed in only one section.

If we were to use the CGI model for creating a database editor, we would need to create an HTML form, pointing its <Form> action to the URL of a CGI program. That CGI program would then need to retrieve the HTML form elements, connect to the database and perform an INSERT.

Listing 2

With Mason, all this becomes much easier because of the relationship between HTML form elements and variables. We will still need two different components, one that presents the form and another that acts on the form's contents. The first component, add-category-form.html (see Listing 2), is a normal HTML form, with a single text field and a “submit” button. The only difference between this form and its non-Mason counterpart is the action attribute in the <Form> tag. In Mason, even a file with an .html suffix is a program and can thus receive input from an HTML form.

Listing 3

The component that handles the input and inserts a new row into the Categories table is called add-category.html (see Listing 3). As is often the case with Mason components, you must first look at the component's final sections (<%once>, <%init> and <%args>) in order to understand what is happening.

In the case of add-category.html, our <%once> section merely defines $dbh, as described above. The <%init> section performs two actions. First, it defines $dbh based on the returned value from “database-connect.comp”. Once the database connection has been established, the <%init> section goes on to INSERT the user's input into the database. Notice how we use DBI's placeholders, shown here as a question mark in the list of VALUES, to avoid potential problems with quoted strings within our SQL query.

The placeholder is filled in with the value of $new_category_name, a scalar variable defined in <%args>:


By defining it there, we indicate that add-category.html must receive an HTML form element new_category_name when it is invoked. We could have given new_category_name a default value; however, this value is crucial to the functioning of add-category.html and must be mandatory.

Depending on whether the SQL INSERT succeeds, the scalar variable $successful_insert is set to true or false. This value is then used in the large if-else statement, to produce HTML that reflects the success or failure of the INSERT shown at the beginning of Listing 3. Notice how $DBI::errstr, the standard DBI error message, is available from within our component.

Adding News

Listing 4

Once we have added one or more categories, we can begin to insert news items into the system. Unlike add-category-form.html, add-news-form.html (Listing 4) will need to connect to the database and cannot be a simple HTML form. This is because we want to present the user with a <select> list of current categories. In order to create this list dynamically, we will need to connect to the database and perform a simple SELECT. Other than that, the HTML form is relatively straightforward. We will use a table to organize the titles and form elements, but it consists of three basic elements: a headline, the body text and a category <select> list.

I decided to do this in a relatively inefficient (but easy to understand) way, using an SQL ORDER BY clause to retrieve names in alphabetical order. In order to keep track of the two different values (ID and name), I put them into the @categories array:

while ($row_ref = $sth->fetchrow_arrayref)
     my ($id, $name) = @$row_ref;
     push @categories, {id => $id,
                         name => $name};

We can then iterate through @categories, placing the category ID as the “value” attribute (which will be submitted to the add-news.html component), but displaying the name of the category:

<select name="category_id">
% foreach my $category (@categories) {
<option value="<% $category->{id} %>">
<% $category->{name} %>
% }
Listing 5

The component that adds news, add-news.html (Listing 5), is almost identical to add-category.html, except it inserts three values rather than just one: the category ID, the headline and the body of the article. If the submission is successful, we tell the user that the article has now been placed in the database.