Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Re: CGI App need direction

by davido (Archbishop)
on Oct 19, 2012 at 23:30 UTC ( #1000069=note: print w/replies, xml ) Need Help??

in reply to CGI App need direction

This can be trivial as a Mojolicious "lite-app". Don't forget to handle file locking, and be sure to deal gracefully with problems such as failure to open the message file. The whole thing including the rendering template could be done without being golfy in around 78 lines of code (I know because that's what I came up with when I tried it myself), about 1/3rd of which is auto-generated for you when you generate a lite app with the "$ mojo generate lite-app" command. The template that you start with, plus the Mojolicious::Lite POD will lead you along the right path.

What's probably not quite so trivial is getting over that initial hump of learning how it all works. But really, the documentation for is pretty good, and in particular, if you focus on creating a "lite-app", your first successful attempt might take an hour or two to work through. And then the next time you have to do something similar, it will take a few minutes to toss together.

Whether you go the Mojolicious route, or Dancer, or even CGI, the first step will be reading the documentation. At that point you'll be able to ask a question that addresses specific areas where you need clarification, rather than "I need the whole thing."

Here is an example Mojolicious application that does basically what you're describing. You might look it over to get some ideas. It doesn't provide a strong separation of concerns between the controller and the data model, but in such a trivial case enhancing the separation might actually add complexity. FWIW, Mojolicious has a CGI compatibility mode, so you can use code very similar to this in your solution.

use Mojolicious::Lite; use Fcntl qw(:flock); use Try::Tiny; use utf8; use feature qw( unicode_strings ); use autodie; use constant FILENAME => 'complaint_file.txt'; app->secret('UNUSED'); helper register_complaint => sub { my $self = shift; my $new_post = $self->param('new_complaint'); $new_post =~ s/^%%ENTRY%%\n//gsmx; # Minor sanitization. try { open my $of, '>>:encoding(UTF-8)', FILENAME; # Append flock $of, LOCK_EX; # Exclusive print {$of} "%%ENTRY%%\n$new_post\n"; flock $of, LOCK_UN; close $of; } catch { $self->app->log->warn($_); }; }; helper list_complaints => sub { my $self = shift; my @posts; try { open my $if, '<:encoding(UTF-8)', FILENAME; # Input local $/ = undef; flock $if, LOCK_SH; # Shared my $post = <$if>; flock $if, LOCK_UN; close $if; @posts = split /^%%ENTRY%%\n/gsmx, $post; shift @posts; } catch { $self->app->log->warn($_); }; chomp @posts; $self->stash(complaints => \@posts); }; any q{/} => sub { my $self = shift; $self->register_complaint if length $self->param('new_complaint'); $self->list_complaints; $self->render('index'); }; app->start; __DATA__ @@ index.html.ep % title 'Complaint Department'; <!DOCTYPE html> <html> <head><title><%= title %></title></head> <body> % title 'Complaint Department'; %= form_for '/' => ( method => 'post' ) => begin <h3>Please enter your complaint.</h3> %= text_field 'new_complaint' %= end %== @{ stash('complaints' ) } ? '<h3>Past complaints:</h3>' : ''; <ul> % foreach my $complaint ( @{ stash('complaints') } ) { <li><%= $complaint =%></li> % } </ul> </body> </html>

As a stand-alone application, run it as "./ daemon". It shouldn't require any special handling in a CGI environment so long as your server is configured as it would be for any other CGI script, although if you're still using CGI you ought to consider persistent processes instead.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1000069]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2018-04-19 19:58 GMT
Find Nodes?
    Voting Booth?