My first week of Dancer, Xslate and Bootstrap

As I mentioned last week, I've started working with Dancer in earnest. This week, I climbed three learning curves at the same time: Dancer, Xslate and Bootstrap.

Skeleton before template

I started off with the incredibly-handy "Dancer Cowbell" template by A. Gordon, which is a complete skeleton app that brings together Dancer, Template::Toolkit, Bootstrap, and Font Awesome.

It comes with scripts to download Bootstrap, etc., from various sources. Unfortunately, the day I tried it, GitHub (the source of Bootstrap's custom downloads) was f*cked, so I wound up cobbling together the various bits from other Bootstrap experiments I'd downloaded in the past. Not fun, but not A. Gordon's fault.

Xslate is xcellent

My next challenge was converting it from Template::Toolkit to Xslate. I'd been intrigued by Xslate's design, particularly its speed. Xslate is fast, at least if you have a C compiler and a persistent application. It also has some interesting template composition capabilities, more akin to "roles" than just bare includes.

For example, here's what one of my view templates looks like:

:cascade wrapper with macros, header, footer

: around title -> {
  About
:}

: around pagestyle -> {
  : stylesheet("about")
:}

: around content -> {
    <h1>About my project</h1>
    <p>Blah blah blah...</p>
:}

The interesting thing is that the "cascade" command combines four other templates, the HTML wrapper, some header HTML, some footer HTML, and macro definitions (the "stylesheet()" function). Then my page template just defines things to replace at various places in the cascade. The "title" and "pagestyle" blocks get inserted into the HTML header section. The "pagestyle" is defined using a macro from the macro sheet (and maps to a stylesheet link with a static path to "about.css" for page-specific layout). And the "content" block gets dropped into the HTML body section in the wrapper.

What about that "header" -- where does that go? Check out the header template:

: before content -> {
  <div class="masthead row">
    <!-- Bootstrap navigation would go here -->
  </div>
  <hr>
:}

See the "before content" directive? It does what you would think, composes the header before the content block in the wrapper. The footer uses an "after" directive the same way.

That's a long digression on Xslate, but I'm really happy with it so far. My view templates are stripped down to the bare minimum of information related to that view, yet can stuff information into any other spot in the composed template. It took a while to wrap my head around what that means.

I think about it like this: the wrapper template defines where things go, but doesn't actually pull them in the way a template would "include" another template traditionally. It's purely a framework of placeholders. Then, other templates customize those placeholders, saying if they go before, after or replace them.

If I want a different header for some page, I don't need a different wrapper to include it (which would duplicate things in the wrapper I might need to then keep in sync), I just need to compose a different header template in the page template cascade. Cool!

But what about Dancer?

Even before I fully wrapped my head around Xslate, I got down to business with Dancer. I spent a while reading various Dancer tutorials:

I decided to start with the static pages, and created simple routes with matching template names.. This was trivially easy, the "hello world" of web development.

get '/' => sub {
  template 'index';
};

for my $p (qw/about faq tos privacy help/) {
  get "/$p" => eval qq|sub { template '$p' }|;
}

I intentionally did not use Dancer's 'auto_page' config option, which will match simple routes to matching templates in the view directory because I don't want all the decomposed xslate templates to become valid routes.

After copying and pasting some examples from the Bootstrap site, I finally got the static pages looking loosely like what I envisioned (albeit with boilerplate text), and I could click around the navigation and the whole thing started looking like a real site. Woohoo!

Users and passwords and hashes, oh my!

With the static shell done, I turned to the next logical task: user registration and login/logout. I already had a half-done user model from some backend prototyping, but it had no concept of password (hashed, of course), so that had to be added.

I spent a little while getting up to speed on bcrypt options on CPAN. There was an interesting Dancer plugin, Dancer::Plugin::Passphrase that I considered, but ultimately I decided that the controller really shouldn't be handling password hashing and that it should live within the model.

I considered Authen::Passphrase and loved everything about it except for all its dependencies -- it gives you tools for every reasonable (and unreasonable) password hashing scheme, even if you only need one. Ugh.

So then I looked at how Dancer::Plugin::Passphrase was using Crypt::Eksblowfish::Bcrypt to see if I could just crib that... and then I decided I was spending way too much time in the weeds and chose to use Authen::Passphrase (BlowfishCrypt algorithm) after all.

Fold, spindle, mutiliate

Forms and form building modules looked like another tarpit and I decided to go around. I worked up simple registration and login forms by hand using some Bootstrap sample code, skipped all validation for now (naughty!), and created some POST handlers. Eventually, I'll go back and look to form builders and validators, but it's easy to lose a day browsing CPAN and I didn't have a day to waste.

In case any other HTML newbie is out there doing things by hand, make sure your inputs have a "name" property if you want them submitted. For whatever reason the code samples omitted them and I spent a long while wishing I had hair to tear out in frustration when my form handling code didn't work. (Yes, a decent form builder would have saved me this embarrassment. Oh, well.)

With that fix, user registration worked.

Doing sessions the not-so-easy way

By definition, "logging in" means a change in state, so I needed sessions to manage state. And of course, Dancer had plenty of session managers to choose from. Dancer::Session::Cookie was the first I tried. I've been intrigued by the concept of maintaining state with clients instead of a server and wanted to give it a try. (No, I won't get drawn into arguments over that here. Trust that I've read the relevant papers about it and have a sense of pros and cons and caveats.)

It worked great, right up until I wanted to log out. I couldn't log out without manually deleting the cookie!. WTF? Turns out it's a bug in how Dancer::Session::Cookie does session destruction. I filed a pull request with a trivial fix and then switched to the other quick-and-dirty developer-friendly option, keeping state with files. I picked Dancer::Session::JSON. Boom! Login and out working.

[After spelunking in the Dancer codebase, I also took some time to explore what the not-yet-released Dancer 2 code is doing for sessions, filed half a dozen issues to address problems I saw, and also filed a pull request to improve the abstraction model.]

Now that I had logged-in and logged-out states, I started tweaking the header templates to change the navigation depending on the users' logged-in or logged-out status. E.g. toggling between "login" and "logout" links and so on.

After that, it's still not much of a site, but it's definitely not "Hello World" anymore.

What's next

I'm now starting to work on email verification and password reset. Both of those have a similar process model requiring a token to be emailed to a user and taking action based on the resulting click. I signed up with Postmark and tested it out with WWW::Postmark. I'll use that for emailing the tokens. At first, it will probably be direct from the app, but eventually, I'll move that into an offline process.

Once that's done, I'll be turning to the "logged in" experience, connecting the site up to the backend data.

Summary

I'm feeling really good about how quickly things came together. After starting from almost zero, here's what I've got after my first week with Dancer, Xslate and Bootstrap:

  • Static pages
  • User registration
  • User login/logout (with navigation changes based on state)
  • Password change
  • Well-factored templates
  • Half a dozen or issues filed or patches sent for things discovered along the way

See you on #dancer...

This entry was posted in perl programming and tagged , , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

9 Comments

  1. Joel Berger
    Posted December 7, 2012 at 5:27 pm | Permalink

    Have you tried Mojolicious? I have never had any problems with sessions, and I think you would avoid that mess with the routing (eek!).

    I don't now how XSlate compares to Mojo's internal templating engine (the one it ships with, which I really like). Also I know that there are ways to integrate other templating engines, so perhaps that will work too?

    As to the password, I love DBIx::Class::EncodedColumn for this! Yes its for use with DBIx::Class and I don't know if you are going that route, but it makes passwords unbelievably simple!

    You are welcome to peruse my code for Galileo. Galileo the project I used to get myself down this same path to learning these tools. Good luck with your adventure!

    • Olivier Mengué
      Posted December 13, 2012 at 12:15 pm | Permalink
      • Joel Berger
        Posted December 13, 2012 at 4:44 pm | Permalink

        So I can't Devel::Cover test the templates. Actually the only reason I filed the bug is that I think it CAN be cover tested, with a little work. Oh well, nothing's perfect. :-)

  2. Posted December 7, 2012 at 8:40 pm | Permalink

    Mojo has never really appealed to me. I tend to prefer working with individual tools than all-in one frameworks.

  3. Peter Corrigan
    Posted December 10, 2012 at 4:45 am | Permalink

    Brilliant post and thank you for sharing. Really interesting to read about your thought processes/modus operandi on getting to grips with a new framework, and about module selection. Good to hear that others can spend time "in the weeds" and need to skirt around tarpits, and can skip form validation while in knowledge acquisition mode. Salutary and inspiring that you could contribute already to Dancer2.

    • Posted December 10, 2012 at 9:10 am | Permalink

      You're welcome! I'm going to try to write about my progress roughly weekly if I continue to discover things worth sharing.
      Hopefully, if I'm doing something really boneheaded, someone will point out the errors of my ways. :-)

  4. Aaron Trevena
    Posted December 10, 2012 at 10:01 am | Permalink

    Hi David,

    I'd definately reccomend using HTML::FormHandler, it's very much a "do one thing well" tool, but has a good ecosystem of plugins.. it also comes with a nice bootstrap theme that just works, and I've added a handy js validation plugin to - have a look at http://formhandler-perl.dotcloud.com/ to see it in action (and see the github source)

    • Posted December 10, 2012 at 12:27 pm | Permalink

      Thank you for the recommendation and the example link. I'll look at that one first. A form builder that plays nice with Bootstrap would make things a lot easier.

  5. Perrin Harkins
    Posted January 9, 2013 at 3:29 pm | Permalink

    I'm enjoying the series, especially hearing details about Xslate. Thanks for posting it.

2 Trackbacks

© 2009-2014 David Golden All Rights Reserved