Table of Contents | Foreword | Preface
Chapters: 1 2 3 4 5 6 7 8 9 10 11 12
Appendices: A B C D
Glossary | Colophon | Copyright

Chapter 8: Building a Mason Site

This chapter covers, in detail, a full-fledged working web application. Our application is the Perl Apprenticeship site at http://apprentice.perl.org/. Back at O'Reilly's 2001 Open Source Conference, Adam Turoff suggested that the Perl community needed a site where people who had project ideas, but either not enough time or not enough expertise, could hook up with other programmers who could supply the missing pieces.

An experienced developer with a really neat idea and not nearly enough time to do it can post a project idea and offer to mentor a less experienced developer in its implementation. Conversely, a less experienced developer with a really neat idea who isn't quite sure how to go forward on it can look for a mentor to help him bring that idea to life.

This is a pretty basic database-backed web application, the kind of thing that Mason gets used for all the time. It didn't require anything too terribly complicated, but it shows off a number of Mason's features quite well, including how components can be used to isolate individual site elements, autohandlers and dhandlers, and a simple use of <%method> blocks.

One thing worth noting is that for database access we chose to use Alzabo, which is a project created and maintained by Dave Rolsky. Alzabo is a database-to-object mapper built on top of the DBI. It allows us to easily create Perl objects representing things in our database, like users or projects. We will not be going into detail on our schema or our Alzabo-related code here, as this is largely incidental to the goal of this chapter. Our hope is that if you don't understand any particular piece of the Alzabo functionality, you can just treat it as pseudocode.1 More information on Alzabo is available online at http://www.alzabo.org/. Alzabo is also available from the CPAN.

The code for the site is available at this book's site, http://www.masonbook.com/. This includes an installer that should help you get the site up and running without too much trouble.2

Functionality

The first issue at hand is determining what sort of functionality the site has to have in order to be useful. Our site is fairly simple. It needs to implement the following features:

Directory Layout

Because of the nature of Mason's autohandler feature,

directory layout is actually an important consideration when designing a site. Of course, you can always override a component's inheritance and inherit from any other component, but it makes sense to come up with a directory layout that minimizes the need to do this.

In the case of the Apprenticeship site, we only have one "skin" we want to apply to all components. This is done in the top-level autohandler. Our subdirectories are then used to implement access controls and dhandlers. Table 8-1 shows our directory layout.

Directory Purpose
/ Contains most of the components that can be viewed by any user.
/users Contains components related to user accounts such as new user sign-up.
/project Contains a single dhandler that displays a project.
/logged_in Contains components accessible only to logged-in users such as new project creation.
/admin Contains components accessible only by site administrators.
/lib Contains components used by other components. These are not called as top-level components.
Table 8-1. Apprentice site layout

File Extensions

We decided to use several different extensions for our

components. Files ending in .html are top-level components processed by Mason, like /index.html. Files ending in .mas are called only by other components and are not accessible from a browser. In addition, we have a file ending in .css that is processed by Mason. This is our stylesheet.

The site has no images, so we don't need to worry about making sure they are served properly.

Apache Configuration

Our Apache configuration will assume that our document root and component root are the same directory, /home/apprentice/htdocs. This is the simplest solution and is appropriate for a single-purpose web server.

Our configuration in httpd.conf begins as follows:

  PerlModule Apprentice

The Apprentice.pm module loads all the Perl modules used by this application, including various Apache::* modules, Digest::SHA1 , Time::Piece , and others.

  PerlSetVar  MasonCompRoot      /home/apprentice/htdocs
  PerlSetVar  MasonDataDir       /var/mason
  
  PerlSetVar  MasonAllowGlobals  $Schema
  PerlAddVar  MasonAllowGlobals  $User

These two objects will be used throughout almost all of the components of our site. Rather than passing them as arguments to every component, which can become extremely tedious, we will create them in our top-level autohandler and limit their lifetime via the use of local().

  PerlModule HTML::Mason::ApacheHandler
  
  <Directory /home/apprentice/htdocs>
   <FilesMatch "(\.html|\.css)$">
    SetHandler  perl-script
    PerlHandler HTML::Mason::ApacheHandler
   </FilesMatch>
  </Directory>

As mentioned before, any file ending with .html or .css should be handled by Mason.

  <FilesMatch "(\.mas|handler)$">
   SetHandler  perl-script
   PerlModule  Apache::Constants
   PerlHandler "sub { return Apache::Constants::NOT_FOUND }"
  </FilesMatch>

There's no reason to let anyone see our .mas components or our autohandlers and dhandlers, so in the interests of security we block them out. We return a NOT FOUND status so that a curious script kiddie won't even know that these files exist.

That's all we need in our Apache configuration to get this site up and running.

The Components

Now that the preliminaries are out of the way, it is time to look at the components that make up this site. We will not be looking at them in line-by-line detail, since this would be excruciatingly dull for all of us. In addition, since a number of components are conceptually similar to one another, we will not show the source for every component, instead saying something along the lines of "this one is mostly like that other one we looked at back there." But if you don't believe us, fear not, because this site's full source code is available at http://www.masonbook.com/.

It is worth noting that this site does not use all of Mason's features. Trying to create a site that did that would result in a monstrosity of biblical proportions (and that's big!). Instead, we created a clean, working site that is as elegantly designed as possible. We've tried to err on the side of brevity and pedagogy -- we could certainly add more features.

We have done our best to make the HTML in these components compliant with the latest HTML 4.01 Transitional Standard, with one major exception. This standard forbids the presence of forms embedded inside tables, but our design would have been grossly complicated by following this restriction, so we ignored it. Yes, we know this is wrong and bad and that we'll burn in web standards hell for this, but we are lazy and we don't care.

We did our best to keep the HTML in this site relatively simple. For text colors and fonts, we have a simple stylesheet. For layout, we have used the nested tables approach. This produces ugly HTML, but CSS positioning doesn't work with Netscape 4.x or other early browsers. In general, we will not be explaining the HTML portions of the components we examine, since we want to talk about programming with Mason, not how to make nice HTML.

One rule we did follow is that any table or portion of a table, such as a <tr> or <td> tag, must start and end in the same component, because it can be extremely confusing when one component starts a table that another component finishes.

In addition, we have tried to make individual components self-contained whenever possible, so individual components often consist of one or more complete tables. Since tables can be embedded in other tables' cells, this makes it safe to call components from within a single table cell.

The Unrestricted Parts

A good place to start with the site is the index page and the other pages that are viewable by anybody without logging in.

Here are the components, in the order we'll discuss them:

  • /syshandler
  • /news.mas
  • /project/dhandler
  • /autohandler
  • /featured_project.mas
  • /users/new_user.html
  • /apprentice.css
  • /all_projects.html
  • /users/user_form.mas
  • /left_side_menu.mas
  • /search_results.mas
  • /users/new_user_submit.html
  • /lib/url.mas
  • /lib/paging_controls.mas
  • /users/login_submit.html
  • /latest_projects.mas
  • /lib/redirect.mas
  • /users/logout.html
  • /lib/format_date.mas
  • /lib/set_login_cookie.mas
  • /users/forgot_password.html
  • /index.html
  • /user.html
  • /users/forgot_password_submit.html
  • /welcome.mas
  • /login_form.html
  • /show_category.html
  • /browse.html
Table 8-2.

These components form the bulk of the site, with the remainder being those pieces intended for logged-in users and site administrators.

Components with Access Controls

The components we just looked at are available to anybody who comes to the site, with no login required. The rest of the components are divided into two directories: one for logged-in users and the other for site administrators. We will start with the components available for logged-in users only. They are:

These components are all about editing things on the site. Let's take a look.

The last components we have to look at are in the /admin directory. These are:

All Done

And that is our site. Putting this site together took maybe 30-40 person-hours from start to finish, which is not too bad. Plenty of that time was spent fiddling with HTML, since that is not our strongest area. Doing this as a traditional CGI application without Mason would probably have either taken much longer to achieve a similar level of code reuse or just ended up as a sloppier application.

Further Directions

As we mentioned at the beginning of this chapter, we wanted to make this site small enough to show you in a single chapter (albeit a rather long chapter), and we sometimes avoided using some features of Alzabo that could have simplified some of the code in order to avoid getting sidetracked into an Alzabo how-to. When you're designing your own sites, you won't have these constraints. Here are some things you might try adding to this site:

Footnotes

1. Or pseudopseudocode, since it's actually code. -- Return.

2. Famous last words, no doubt. Bug reports are always welcome, of course. -- Return.

3. See Chapter 11 for some session code examples. -- Return.