These days it seems like everybody and their dog wants to create something like Ruby on Rails. While there are a number of competitors out there, the only one I have any experience with is Catalyst, written in Perl. I had a commit bit on that project once and it looks really promising, but it’s “some assembly required” (or at least, it was last time I checked). It has an overwhelming number of options and tries very hard to not tie your hands at all. It has a great dispatching action, but in the end, if you’re new to Catalyst, or worse, new to Perl, the number of different options and how to hook them together can seem daunting. Once you get them working, though, Catalyst is pretty fun.

For various reasons, I’ve moved on from that project, but the idea of “just get it done” is very appealing to me. Since I’m primarily a Perl programmer nowadays, when I saw that Jifty had been released, I was pretty excited. I know Jifty’s primary architect, Jesse Vincent, and have a lot of respect for him, so that helped me be excited even though Jifty is yet another web application framework. (It’s also worth noting that Jifty is put out by the makers of RT, a very popular request tracker, so these folks know a good thing or two about progamming.) However, Jesse might not like me mentioning Rails and Jifty in the same blog post since Rails isn’t even mentioned in the Jifty docs. To be fair, Jifty is not a port of Rails and doesn’t pretend to be. It’s just your basic AJAXified full-stack continuation-based Web Application Platform. Hmm, how can I make this not boring? I know, I’ll write this blog entry while I work through the tutorial. Something has to break, I’m going to do something stupid, or some other problem will arise.

Installing Jifty

Let’s see, Jifty depends on over 60 modules from the CPAN. This is going to be a nightmare to install. I first tried installing Jifty a couple of days after it came out and it installed fine, but I couldn’t get it to work, so I have a bit of trepidation here (plus, I like Jesse, so if something fails while I’m writing this, I don’t want to make him look bad).

cpanp -i Jifty

Wow. I had most of them installed already. In fact, there were only four other modules I needed:

  • Object::Declare
  • PAR::Dist::FromCPAN
  • Scalar::Defer
  • JSON::Syck

Of course, I’m kind of a Perl power user, so it’s quite possible you’ll have more uninstalled dependencies. Still, those four modules installed without a hitch and then the Jifty install went smoothly (note, if you’ve not used cpanp, it’s the command line script for CPANPLUS and it installed the four modules automatically, after asking if it was OK. There was no other work on my part other than typing “yes”).

Creating my first model.

So I start the tutorial.

jifty app –name MyWeblog

Look familiar? That creates the shell of your application. I cd MyWeblog/ and look around. The first thing I notice is that web/static/ doesn’t exist, even though it’s listed in the tutorial. Turns out it’s in share/web/static/. Ah well, I’m used to subtle discrepancies in docs. So I start creating my weblog

The first thing I need to do is post to my weblog, so I create a model for it.

jifty model –name Post

Hmm, I see that it also created a t/00-module-Post.t. It’s probably just a test to make sure I can load my model, but even though the docs don’t list this, I go ahead and run it.

MyWeblog $ prove -lv t
t/00-model-Post....1..11
ok 1 - use MyWeblog::Model::Post;
ok 2 - Found a system user
ok 3 - Post create returned success
ok 4 - New Post has valid id set
ok 5 - Create returned the right id
ok 6 - Post create returned another value
ok 7 - And it is different from the previous one
ok 8 - Finds two records
ok 9 - Finds one record with specific id
ok 10 - Deleted row is gone
ok 11 - Still one left
Done.
ok
All tests successful.
Files=1, Tests=11,  6 wallclock secs ( 2.11 cusr +  0.53 csys =  2.64 CPU)

(Those tests might seem slow, but I have some pretty heavyweight processes running in the background for some other work I’m doing).

Whoa! It’s already verifying that my model works, even though I’ve not specified anything. I do a bit of digging around (using Devel::Trace to get a full execution flow dumped to a log) and find out that internally it’s using DBI, the standard database interface, but I want to get back to work and I figure I’ll sort this out later.

Adding a simple schema

I do a quick vim lib/MyWeblog/Model/Post.pm and I add the following lines:

column title => 
       type is 'text',
       label is 'Title',
       default is 'Untitled post';

column body => 
       type is 'text',
       label is 'Content',
       render_as 'Textarea';

Hey, that’s about as declarative as you can get. I like that.

So now it’s time to open up my database and create the tables. Hey, I don’t have to do that!

MyWeblog $ jifty schema --setup
INFO - Generating SQL for application MyWeblog...
INFO - Using Jifty::Model::Session
INFO - Using Jifty::Model::Metadata
INFO - Using MyWeblog::Model::Post
INFO - Using Jifty::Model::Schema
INFO - Set up version v0.0.1, jifty version 0.607220

Well, I’m curious, so I look in the etc/config.yml file to see where the database is and it’s an SQLite database in my current directly, named myweblog. By default, Jifty uses SQLite so you can play with it, but Jifty::Config has the information about how to connect it to other databases such as PostgreSQL or MySQL.

sqlite3 myweblog
sqlite> .tables
_db_version      _jifty_metadata  _jifty_sessions  posts          
sqlite> .schema posts
CREATE TABLE posts (
  id INTEGER PRIMARY KEY NOT NULL  ,
  title text  DEFAULT 'Untitled post' ,
  body text   
);

Hey, I didn’t even have to touch the database to create that. Nice.

Running the app

Now it’s time to start the server.

MyWeblog $ ./bin/jifty server
INFO - You can connect to your server at http://localhost:8888/

Well, uh, I haven’t created view yet. I wonder what I’m going to get. I go to http://localhost:8888/ and hey, I get a Pony! I also get full online documentation and and administrative console. The adminstrative console already gives me full CRUD (Create, Read, Update, Delete) access to my database. Nice. Jifty comes with its own (slow) Webserver so you can test right away without configuring Apache, IIS, or whatever you use.

I shut the server down and now edit share/web/templates/post (this time the documentation has the path right).

Creating my view

<%init>
my $action = Jifty->web->new_action(class =>'CreatePost');
</%init>

<&|/_elements/wrapper, title => "Post to your weblog" &>
<% Jifty->web->form->start() %>
<% Jifty->web->form->next_page( url => '/') %>
<% $action->form_field('title') %>
<% $action->form_field('body') %>
<% Jifty->web->form->submit( label => 'Post' ) %>
<% Jifty->web->form->end() %>
</&>

Now the Jifty docs diverge. I can create the boring way of listing all of my post entries, or I can create the nifty AJAX way. I’m daring. I’m going for the latter.

vim share/web/templates/index.html

And add this:

<&|/_elements/wrapper, title => Jifty->config->framework('ApplicationName') &>

<% Jifty->web->region(name => "myweblog-posts",
                      path => "/fragments/page_of_posts") %>
</&>

Side note: If you’re wondering about all of the work to escape HTML entities for this weblog, I have a mapping in my .vimrc to this function:

function! HTMLEscape()
    %s/&/\&amp;/g
    %s/>/\&gt;/g
    %s/</\&lt;/g
    echo "HTML special characters escaped"
endfunction

And back to the show.

MyWeblog $ mkdir share/web/templates/fragments
MyWeblog $ vim share/web/templates/fragments/page_of_posts

<%args>
$page => 1
</%args>
<%init>
my $posts = MyWeblog::Model::PostCollection->new();
$posts->unlimit();
$posts->set_page_info( current_page => $page,
                       per_page     => 25
                     );
$m->out("No items found.") if ($posts->pager->total_entries == 0);

</%init>
% if ($posts->pager->last_page > 1) {
   Page <% $page %> of <% $posts->pager->last_page %>
% }
<dl class="list">
% while (my $post = $posts->next) {
 <dt><%$post->title%></dt>
 <dd><%$post->body%></dd>
% }
</dl>

% if ($posts->pager->previous_page) {
  <% Jifty->web->link( label => "Previous Page", onclick => { args => { page => $posts->pager->previous_page } } ) %>
% }
% if ($posts->pager->next_page) {
  <% Jifty->web->link( label => "Next Page", onclick => { args => { page => $posts->pager->next_page } } ) %>
% }

Now it’s time to fire up the Web server again. I’m pretty nervous now because I’m writing this as I go along and I don’t want this to fail, but I’ve done a lot of stuff here and I’m used to stuff failing. But I go to http://localhost:8888/post/ and there’s a post page! I type in a post, hit submit and it tells me I’ve create a post. I click the ‘x’ button on the ‘create’ message and it just fades away, leaving just the post for me.

Adding to the menu

Reading along in the docs, they want me to add “Post” to the navigation menu. OK.

MyWeblog $ mkdir share/web/templates/_elements
MyWeblog $ vi share/web/templates/_elements/nav

And I add this:

<%init>
my $top = Jifty->web->navigation;
$top->child( Home => url => "/");
$top->child( Post => url => "/post",
                     label => "Post Article");
</%init>

I fire up the server again and the admin and documenation links are gone, but there’s my post button. Adding another entry works just fine.

By default, admin mode is ‘on’ and Jifty has a large red bar across the top of the screen letting us know this. I click on its admin link and I’m back at the admin page. From there, I try editing and adding posts and yup, AJAX is working just fine. There doesn’t seem to be a ‘delete’ link, like I wrote earlier, but that’s OK.

Conclusion

Well, that was painless. Everything just worked. That’s what app development should be. After I wrote this, I browsed through the docs a bit more and they are definitely a work in progress. Not everything was as obvious as it should be and some things didn’t work (jifty schema –man, for example). Also, even though the default text was telling me that column declaration syntax was in Jifty::DBI::Schema, I accidentally used the syntax shown in Jifty::Param::Schema and Jifty built a database, and the checkbox got rendered as a regular text input box. Once I consulted the right docs (perldoc Jifty::DBI::Schema), it worked just fine. Given how young this framework is, I’m pleasantly surprised.

I’m sure some of you are thinking “that was stupid. Why should he be pleased about that? Rails already does all that and more.” This is true, but if you’re in a Perl shop and your company doesn’t want other languages used (this is very common), then having a good Perl alternative is nice and I’m quite happy to see this on here. Catalyst is also nice, but I’m keen to see what Jifty is going to do.

If you really want to see Jifty in action, check out Hiveminder. It’s a ridiculously easy to use task manager (oh, and free, too).