• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Introduction to Jifty
 

Introduction to Jifty

on

  • 5,628 views

A brief introduction to Jifty using a demo app that emulates Qublog

A brief introduction to Jifty using a demo app that emulates Qublog

Statistics

Views

Total Views
5,628
Views on SlideShare
5,547
Embed Views
81

Actions

Likes
2
Downloads
18
Comments
0

3 Embeds 81

http://qublog.net 71
http://www.slideshare.net 9
http://192.168.10.100 1

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Introduction to Jifty Introduction to Jifty Presentation Transcript

    • Introduction to Jifty Sterling Hanenkamp, PPW 2008
    • I Work for a Living
    • I Work for a Living • Contract work / Billable Hours: How do I track them?
    • I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do?
    • I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do? • Reliable Memory: Did I do that? How? When? Why?
    • I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do? • Reliable Memory: Did I do that? How? When? Why? • Task Lists: What should I do next?
    • Existing Solutions Time Sheet
    • Existing Solutions Planner
    • Existing Solutions Scratch Paper
    • Existing Solutions
    • Existing Solutions Things Sunbird Day Planner Hiveminder Entourage Stikkit iCal/Apple Mail Lightning OmniFocus
    • Qublog
    • Qublog • I don’t want to store this information in four places
    • Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus
    • Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time
    • Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while)
    • Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while) • It’s written using Jifty
    • Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while) • It’s written using Jifty • We’re going to look at how I did it to explain Jifty
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • What’s it look like?
    • Qublog
    • Qublog • Provides a Journal for keeping thoughts
    • Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks
    • Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent
    • Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent • Timers are grouped into Entries to sum up work for reporting
    • Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent • Timers are grouped into Entries to sum up work for reporting • Comments also connect with Tasks to keep track of what’s next
    • This is a talk about Jifty
    • This is a talk about Jifty • Not Qublog • Okay, so let’s see if we can build QublogMini in the time remaining...
    • Install Jifty As with “that-other-framework,” the worst part is over when you finish the install.
    • Install Jifty
    • Install Jifty • Method 1: Shipwright
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty “notest” saves ~60 minutes according to Audrey • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty “notest” saves ~60 minutes according to Audrey • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty “notest” will get you no support according to Jesse
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty • ActiveState installation on Windows: http://jifty.org/view/DownloadJifty
    • Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty • ActiveState installation on Windows: http://jifty.org/view/DownloadJifty • Jifty is in Debian unstable
    • % jifty app --name QublogMini
    • % jifty app --name QublogMini Creating new application QublogMini Creating directory QublogMini/lib Creating directory QublogMini/lib/QublogMini Creating directory QublogMini/bin Creating directory QublogMini/etc Creating directory QublogMini/doc Creating directory QublogMini/log Creating directory QublogMini/var Creating directory QublogMini/var/mason Creating directory QublogMini/share Creating directory QublogMini/share/po Creating directory QublogMini/share/web Creating directory QublogMini/share/web/templates Creating directory QublogMini/share/web/static Creating directory QublogMini/lib/QublogMini/Model Creating directory QublogMini/lib/QublogMini/Action Creating directory QublogMini/t Creating configuration file QublogMini/etc/config.yml
    • % cd QublogMini % find . -type f
    • % cd QublogMini % find . -type f ./bin/jifty ./etc/config.yml ./Makefile.PL
    • % ./bin/jifty server
    • % ./bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost:8888/
    • % ./bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost:8888/
    • Take a Look
    • OMG! Ponies!!!
    • Not a very interesting journaling app... let’s fix it.
    • % ./bin/jifty model --name Comment
    • % ./bin/jifty model --name Comment Writing file t/00-model-Comment.t Writing file lib/QublogMini/Model/Comment.pm
    • % ./bin/jifty model --name Comment Writing file t/00-model-Comment.t Writing file lib/QublogMini/Model/Comment.pm % vim lib/QublogMini/Model/Comment.pm
    • package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { };
    • package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ); column name => type is 'text', label is 'Name', render as 'textarea'; };
    • % bin/jifty server
    • % bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using QublogMini::Model::Comment, as it appears to be new. INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost: 8888/
    • % bin/jifty model --name Timer
    • % bin/jifty model --name Timer Writing file lib/QublogMini/Model/Timer.pm Writing file t/00-model-Timer.t
    • % bin/jifty model --name Timer Writing file lib/QublogMini/Model/Timer.pm Writing file t/00-model-Timer.t % vim lib/QublogMini/Model/Timer.pm
    • package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { };
    • package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { column started_on => label is 'Started on', filters are qw( Jifty::DBI::Filter::DateTime ); column stopped_on => label is 'Stopped on', filters are qw( Jifty::DBI::Filter::DateTime ); column comments => references QublogMini::Model::CommentCollection by 'timer'; }; sub since { '0.0.2' }
    • package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ), ; column name => type is 'text', label is 'Name', render as 'textarea', ; };
    • package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ), ; column name => type is 'text', label is 'Name', render as 'textarea', ; column timer => label is 'Timer', since '0.0.2', references QublogMini::Model::Timer; };
    • % bin/jifty server
    • % bin/jifty server WARN - Application schema version in database (v0.0.1) doesn't match application schema version (0.0.2) WARN - Automatically upgrading your database to match the current application schema. Jifty version 0.809130 up to date. Jifty::Plugin::LetMe version v0.0.1 up to date. Jifty::Plugin::SkeletonApp version v0.0.1 up to date. Jifty::Plugin::REST version v0.0.1 up to date. Jifty::Plugin::Halo version v0.0.1 up to date. Jifty::Plugin::ErrorTemplates version v0.0.1 up to date. Jifty::Plugin::OnlineDocs version v0.0.1 up to date. Jifty::Plugin::CompressedCSSandJS version v0.0.1 up to date. Jifty::Plugin::AdminUI version v0.0.1 up to date. INFO - Generating SQL to upgrade QublogMini v0.0.1 database to v0.0.2 INFO - Upgrading through 0.0.2 INFO - Running upgrade script INFO - Upgraded to version v0.0.2 INFO - You can connect to your server at http://localhost:8888/
    • package QublogMini::Model::Timer; # ... sub name { my $self = shift; $self->started_on . ' to ' . $self->stopped_on }
    • % bin/jifty model --name Entry
    • % bin/jifty model --name Entry Writing file t/00-model-Entry.t Writing file lib/QublogMini/Model/Entry.pm
    • % bin/jifty model --name Entry Writing file t/00-model-Entry.t Writing file lib/QublogMini/Model/Entry.pm % vim lib/QublogMini/Model/Entry.pm
    • package QublogMini::Model::Entry; use Jifty::DBI::Schema; use QublogMini::Record schema { };
    • package QublogMini::Model::Entry; use Jifty::DBI::Schema; use QublogMini::Record schema { column name => type is 'text', label is 'Name', is mandatory; column url => type is 'text', label is 'Name'; column timers => references QublogMini::Model::TimerCollection by 'entry'; }; sub since { '0.0.3' }
    • package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { # ... column entry => label is 'Entry', since '0.0.3', references QublogMini::Model::Entry; # ... }; sub name { my $self = shift; my $name = ''; $name .= $self->entry->name . ': ' if $self->entry->id; $name .= $self->started_on . ' to ' . $self->stopped_on return $name; }
    • --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.2
    • --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.2
    • --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.3
    • % bin/jifty server
    • % bin/jifty server WARN - Application schema version in database (v0.0.2) doesn't match application schema version (0.0.3) WARN - Automatically upgrading your database to match the current application schema. Jifty version 0.809130 up to date. Jifty::Plugin::LetMe version v0.0.1 up to date. Jifty::Plugin::SkeletonApp version v0.0.1 up to date. Jifty::Plugin::REST version v0.0.1 up to date. Jifty::Plugin::Halo version v0.0.1 up to date. Jifty::Plugin::ErrorTemplates version v0.0.1 up to date. Jifty::Plugin::OnlineDocs version v0.0.1 up to date. Jifty::Plugin::CompressedCSSandJS version v0.0.1 up to date. Jifty::Plugin::AdminUI version v0.0.1 up to date. INFO - Generating SQL to upgrade QublogMini v0.0.2 database to v0.0.3 INFO - Upgrading through 0.0.3 INFO - Running upgrade script INFO - Upgraded to version v0.0.3 INFO - You can connect to your server at http://localhost:8888/
    • Ponies are great!
    • Ponies are But where’s the UI? great!
    • # Dispatcher maps URLs to Views % vim lib/QublogMini/Dispatcher.pm
    • package QublogMini::Dispatcher; use Jifty::Dispatcher -base;
    • package QublogMini::Dispatcher; use Jifty::Dispatcher -base; on '/' => dispatch '/today';
    • package QublogMini::Dispatcher; use Jifty::Dispatcher -base; on '/' => dispatch '/today'; on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; show '/today'; };
    • package QublogMini::View; use Jifty::View::Declare -base; template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; } };
    • template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
    • private template '/timers' => sub { my ($self, $entry) = @_; my $timers = $entry->timers; while (my $timer = $timers->next) { show '/show_comment', $timer->stopped_on, _('Stopped timer.') if $timer->stopped_on; show '/comments', $timer; show '/show_comment', $timer->started_on, _('Started timer.'); } };
    • private template '/comments' => sub { my ($self, $timer) = @_; my $comments = $timer->comments; while (my $comment = $comments->next) { show '/show_comment', $comment->commented_on, $comment->name; } }; private template '/show_comment' => sub { my ($self, $time, $message) = @_; p { { class is 'time' } $time }; p { { class is 'comment' } $message }; };
    • Fine. We already knew that. Where’s the “interface”?
    • template '/today' => page { { title is quot;Today's Journalquot; } form { render_region name => 'add_entry', path => '/add_entry_button', ; }; my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url; }; show '/timers', $entry; } };
    • template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; };
    • template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
    • Where’d it go?
    • Where’d it go? 2 Problems
    • Where’d it go? 2 Problems We need a timer too.
    • Where’d it go? 2 Problems We need a timer too. We need to redraw the journal.
    • package QublogMini::Model::Entry; use Jifty::DBI::Schema; use DateTime; # ... # Add a timer when we add an entry sub after_create { my ($self, $id) = @_; return unless $$id; my $timer = QublogMini::Model::Timer->new; $timer->create( entry => $$id, started_on => DateTime->now, ); return 1; }
    • template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
    • template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
    • # Replace /today with a region template '/today' => page { { title is quot;Today's Journalquot; } render_region name => 'entries', path => '/entries', ; };
    • # Replace /today with a region template '/today' => page { { title is quot;Today's Journalquot; } render_region name => 'entries', path => '/entries', ; };
    • # Add a new entries fragment template '/entries' => sub { form { render_region name => 'add_entry', path => '/add_entry_button', ; }; my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url; }; show '/timers', $entry; } };
    • on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
    • on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
    • on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
    • template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
    • template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
    • # Make our entry form update everything properly template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => [ { submit => $entry_action, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; };
    • # Make our entry form update everything properly template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => [ { submit => $entry_action, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; };
    • Bummer. Wrong Order.
    • Bummer. Wrong Order.
    • on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); # ... $entries->order_by({ alias => $timer_alias, column => 'started_on', order => 'DES', }); set entries => $entries; };
    • on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); # ... $entries->order_by({ alias => $timer_alias, column => 'started_on', order => 'DES', }); set entries => $entries; };
    • We have entries and timers, but what about comments?
    • package QublogMini::Model::Comment; use Jifty::DBI::Schema; use DateTime; # ... sub before_create { my ($self, $args) = @_; $args->{commented_on} = DateTime->now; return 1; }
    • template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; form_submit label => _('Add Comment'), onclick => { region => Jifty->web->current_region, replace_with => '/add_comment_form', }, ; };
    • template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; form_submit label => _('Add Comment'), onclick => { region => Jifty->web->current_region, replace_with => '/add_comment_form', }, ; };
    • template '/add_comment_form' => sub { my $timer = QublogMini::Model::Timer->new; $timer->load_current; # loads the latest running timer my $comment_action = new_action class => 'CreateComment'; render_action $comment_action, [ qw( name ) ]; form_submit label => _('Add Comment'), onclick => [ { submit => { action => $comment_action, arguments => { timer => $timer->id, }, }, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; # ...
    • # ... form_submit label => _('Cancel'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
    • What about Validation
    • What about Validation • Easy
    • What about Validation • Easy • Add a validate_XXX method to the model
    • What about Validation • Easy • Add a validate_XXX method to the model • Let’s try it
    • sub validate_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return (0, 'That does not look like a URL.'); } return 1; }
    • Canonicalization
    • Canonicalization • You can also canonicalize something
    • Canonicalization • You can also canonicalize something • What the heck is that?
    • Canonicalization • You can also canonicalize something • What the heck is that? • Rather than slap their hand, fix it for them
    • Canonicalization • You can also canonicalize something • What the heck is that? • Rather than slap their hand, fix it for them • For example, we could... (but won’t)...
    • sub canonicalize_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; }
    • sub canonicalize_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; Too naïve, I refuse to } implement it!
    • But it was the best I could come up with on sub canonicalize_url { short notice. my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; Too naïve, I refuse to } implement it!
    • Halos
    • Halos
    • Halos
    • Halos I’m the view code for this “frame” in the page!
    • Halos
    • Halos
    • Halos
    • Halos View the HTML source, Luke.
    • Halos
    • Halos
    • Halos
    • Page Info
    • Page Info
    • Page Info
    • Page Info
    • Page Info
    • Page Info
    • Page Info • Click on things to view info
    • Page Info • Click on things to view info • SQL Logging
    • Page Info • Click on things to view info • SQL Logging • SQL Profiling
    • Page Info • Click on things to view info • SQL Logging • SQL Profiling • Template Profiling
    • Developer Mode
    • Developer Mode • Module::Refresh
    • Developer Mode • Module::Refresh • Tracing with Log4Perl
    • Developer Mode • Module::Refresh • Tracing with Log4Perl • Administration Console
    • Developer Mode • Module::Refresh • Tracing with Log4Perl • Administration Console • (actually, that’s Administrator Mode)
    • Deployment
    • Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment)
    • Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported
    • Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported • Use a fast static server to server CSS, JS, images, etc.
    • Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported • Use a fast static server to server CSS, JS, images, etc. • Use CSS::Squish and JS::Squish to help compress and cache things
    • Other Goodies
    • Other Goodies • Several authentication plugins: typical email sign-up login, OpenID, Facebook, LDAP, CAS • Additional CRUD view helpers I haven’t demonstrated • Built-in REST interface • Full I18N support built-in • Several Plugins for lots of things: Comments, Single Page Apps, Client-Side Templating, Charting, Tab helpers • Built-in support for Comet (server push) in addition to Ajax
    • Applications
    • Applications • Hiveminder (http://hiveminder.com)
    • Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org)
    • Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net)
    • Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com)
    • Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com) • CommitBit (http://code.bestpractical.com/)
    • Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com) • CommitBit (http://code.bestpractical.com/) • Ping / Chat / Clock (examples available with Jifty)
    • Jifty Resources
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/)
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org)
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org)
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod)
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod)
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod) • Mailing List: jifty‐devel@lists.jifty.org
    • Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod) • Mailing List: jifty‐devel@lists.jifty.org • IRC Channel: #jifty on irc.freenode.org
    • Qublog • See http://qublog.net • Sample code for QublogMini in SVN: http://qublog.net/svn/QublogMini
    • Thank you!