Here is the entire source for the "almost working" dancr.pl tutorial demo, implemented as an application under Windows/Apache:

[.../htdocs/dancr/lib/dancr.pm]   Note - Changes from "dancer.pl" in yellow...

-----------------------------------------------------------------------------

package dancr;

use strict;
use warnings;

use Dancer2;
use DBI;
use File::Spec;
use File::Slurp;
use Template;

our $VERSION = '0.1';
 
# set 'database'     => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');
# Set the database to live under the application directory...
set 'database'     => 'C:\Apache24\htdocs\dancr\dancr.db';
#set 'session'      => 'Simple';
set 'session'      => 'YAML';
set 'template'     => 'template_toolkit';
set 'logger'       => 'console';
set 'log'          => 'debug';
set 'show_errors'  => 1;
set 'startup_info' => 1;
set 'warnings'     => 1;
set 'username'     => 'admin';
set 'password'     => 'password';
set 'layout'       => 'main';

my $flash;

sub set_flash {
    my $message = shift;

    $flash = $message;
}

sub get_flash {
    my $message = $flash;
    $flash = '';
   
    return $message;
}

sub connect_db {
    my $dbh = DBI->connect("dbi:SQLite:dbname=".setting('database')) or
        die $DBI::errstr;
 
    return $dbh;
}
 
sub init_db {
    my $db = connect_db();
    my $schema = read_file('./schema.sql');
    $db->do($schema) or die $db->errstr;
}
 
hook before_template => sub {
    my $tokens = shift;
 
#    $tokens->{'css_url'} = request->base . 'css/dancr.css';
    $tokens->{'css_url'} = request->base . '/css/dancr.css';
    $tokens->{'login_url'} = uri_for('/login');
    $tokens->{'logout_url'} = uri_for('/logout');
    $flash='';
};
 
get '/' => sub {
    my $db = connect_db();
    my $sql = 'select id, title, text from entries order by id desc';
    my $sth = $db->prepare($sql) or die $db->errstr;
    $sth->execute or die $sth->errstr;
   
    template 'show_entries.tt', {
        'msg' => get_flash,
        'add_entry_url' => uri_for('/add'),
        'entries' => $sth->fetchall_hashref('id'),
    };
   
};
 
post '/add' => sub {
    if ( not session('logged_in') ) {
        send_error("Not logged in", 401);
    }
 
    my $db = connect_db();
    my $sql = 'insert into entries (title, text) values (?, ?)';
    my $sth = $db->prepare($sql) or die $db->errstr;
    $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;
 
    set_flash('New entry posted!');
    redirect '/';
};
 
any ['get', 'post'] => '/login' => sub {
    my $err;
    my $session = session;
   
    if ( request->method() eq "POST" ) {
        # process form input
        if ( params->{'username'} ne setting('username') ) {
            $err = "Invalid username";
        }
        elsif ( params->{'password'} ne setting('password') ) {
            $err = "Invalid password";
        }
        else {
            session 'logged_in' => true;
            set_flash('You are logged in.');
            return redirect '/';
        }
   }
 
   # display login form
   template 'login.tt', {
       'err' => $err,
   };
 
};
 
get '/logout' => sub {
   app->destroy_session;
   set_flash('You are logged out.');
   redirect '/';
};
 
init_db();
start;

true;

-----------------------------------------------------------------------------


[http.conf]

<Directory "C:/Apache24/htdocs/dancr">
    AllowOverride None
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    Order allow,deny
    Allow from all
    AddHandler cgi-script .cgi
</Directory>
 
ScriptAlias /dancr "C:/Apache24/htdocs/dancr/public/dispatch.cgi"



It all seems to boil down to the "my $flash;" global variable that never gets set correctly in "sub set_flash" (or read in get_flash)... I think it must be something about variable scope since the global and the subs are not part of a route in the context of the app...

---------------------------------
my $flash;

sub set_flash {
    my $message = shift;

    $flash = $message;
}

---------------------------------

Thank you for any input about this... I'm sure it's something obvious that I'm missing... but I'm hoping I can be enlightened...

Prairie Nyx


On Sat, May 30, 2015 at 10:47 PM, Prairie Nyx <prairienyx@gmail.com> wrote:
Perl Dancer Community:

I am converting from Dancer to Dancer2 (better late than never) and also developing some preliminary curriculum materials for CoderDojo using Perl Dancer2 as a framework for web development.

I started with SawyerX's tutorial page:

   http://search.cpan.org/~xsawyerx/Dancer2/lib/Dancer2/Tutorial.pod

The "dancr.pl" tutorial program ran just fine under the port 3000 server and the tutorial was useful and instructive:

C:\Users\CoderDojo\Perl\Dancer\dancr>perl dancr.pl
>> Dancer2 v0.160001 server 2496 listening on http://0.0.0.0:3000

I ran into an issue when I tried to convert this demo into an app that would run under Apache in a Windows environment, however.

The *crux* of the issue is that the "$flash message" does not work in the app (I suspect because the global variable $flash and the two subroutines are not part of a route, but I could *really* use an explanation, if this issue is obvious to someone:

I created the app as normal:

C:\Apache24\htdocs>dancer2 -a dancr
+ dancr
+ dancr\config.yml
+ dancr\cpanfile
+ dancr\Makefile.PL
+ dancr\MANIFEST.SKIP
+ dancr\bin
+ dancr\bin\app.psgi
+ dancr\environments
+ dancr\environments\development.yml
+ dancr\environments\production.yml
+ dancr\lib
+ dancr\lib\dancr.pm
+ dancr\public
+ dancr\public\dispatch.cgi
+ dancr\public\dispatch.fcgi
+ dancr\public\404.html
+ dancr\public\500.html
+ dancr\public\favicon.ico
+ dancr\public\css
+ dancr\public\css\error.css
+ dancr\public\css\style.css
+ dancr\public\images
+ dancr\public\images\perldancer-bg.jpg
+ dancr\public\images\perldancer.jpg
+ dancr\public\javascripts
+ dancr\public\javascripts\jquery.js
+ dancr\t
+ dancr\t\001_base.t
+ dancr\t\002_index_route.t
+ dancr\views
+ dancr\views\index.tt
+ dancr\views\layouts
+ dancr\views\layouts\main.tt

With the resulting app files, I added the code from the original "dancr.pl" demo to the applications "dancr.pm" module:

package dancr;
use Dancer2;

our $VERSION = '0.1';

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

true;


I had to make the following adjustments to the code for Windows/Apache:

(1) Change the session to YAML

#set 'session'      => 'Simple';
set 'session'      => 'YAML';


(2) Adjust the path for request->base:

#   $tokens->{'css_url'} = request->base . 'css/dancr.css';
    $tokens->{'css_url'} = request->base . '/css/dancr.css';

Everything with the app works as expected *except* for the "$flash message" code:

my $flash;

sub set_flash($message) {
    my $message = shift;

    $flash = $message;
}

sub get_flash {
    my $message = $flash;
    $flash = '';
   
    return $message;
}

I suspect that since these subs are outside a route, perhaps I'm getting an effect about the scope of the variables... but calls to these subroutines do *not* set $flash or $message as expected:

   template 'show_entries.tt', {
   'msg' => get_flash,

   set_flash('New entry posted!');

   set_flash('You are logged in.');

   set_flash('You are logged out.');

For each of these, the $flash variable (which is a free-standing global in the module) is never set... and so the get_flash sub never returns a value.

--



--
Prairie Nyx
prairienyx@gmail.com