Mojolicious::LiteとData::ModelとjQueryでAJAXなチャットを作ってみた

2011年1月10日
| トラックバック(2) Mojolicious::LiteとData::ModelとjQueryでAJAXなチャットを作ってみた

Mojoliciousが1.01になりましたね。

まあ、それとは関係ないですが、jQueryを使ってAJAXなチャットを作ってみたので晒してみようかと思います。
AJAX自体、やった事が無いので、もっと良いやり方があるとは思います。
値の受け渡しはJSONを使ったのですが、Mojolicious側の受け取り方法がよく分からなくて$self->req->jsonとか、Mojo::JSON->newとかやっていたのですが、結果的に普通に$self->paramで受け取れるのがわかって、凄いと思いました。

JavaScript側では、Perlからのtime値をどうやって渡すのかが、調べていてもよく分からなかったので、正解に行き着くのが大変でした。
ミリセカンドで渡す、というのは気づきませんでした。
常識すぎてあまり書かれないんでしょうか…。

#!/usr/bin/env perl
#utf8
# use Acme::PerlTidy;
use utf8;
 
package DataModel;
use base 'Data::Model';
use Data::Model::Schema;
use Data::Model::Driver::DBI;
my $dbfile = qq{$0.db};
my $dsn    = qq{dbi:SQLite:dbname=$dbfile};
my $driver = Data::Model::Driver::DBI->new(
    dsn             => $dsn,
    connect_options => {sqlite_unicode => 1},
);
base_driver($driver);
 
install_model messages => schema {
    key 'id';
    column id  => int  => {auto_increment => 1};
    column msg => char => {required       => 1};
    column ts  => char => {required       => 1};
};
 
unless (-f $dbfile) {
    my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0})
      or DBI->errstr;
    for my $sql (__PACKAGE__->as_sqls) {
        $dbh->do($sql) or die $dbh->errstr;
    }
    $dbh->disconnect;
}
 
package main;
use Mojolicious::Lite;
use Mojo::Util qw/md5_sum/;
app->secret(md5_sum $0 )->log->level('debug')->path(qq{$0.log})
  ->debug(app->secret);
app->helper(model => sub { my $dbh = DataModel->new });
 
get '/' => 'index';
 
get '/json' => sub {
    my $self     = shift;
    my $model    = $self->model;
    my $messages = [
        $model->get(
            'messages' => {
                where => [id  => {'>' => $self->param('from_id')}],
                order => [{id => 'ASC'}],
            }
        )
    ];
    my @json;
    for my $msg (@{$messages}) {
        push @json,
          { id  => $msg->id,
            msg => $msg->msg,
            ts  => $msg->ts,
          };
    }
    $self->render(json => [@json]);
} => 'json';
 
post '/json' => sub {
    my $self  = shift;
    my $time  = time;
    my $model = $self->model;
    $model->set(
        'messages' => {
            msg => $self->param('msg'),    # jsonもparamで取れる
            ts  => $time,
        }
    );
};
 
app->start;
__DATA__
@@ index.html.ep
% layout 'main';
%= javascript begin
jQuery(function($) {
    $("#message").focus();
 
    var params = $.extend({
        refresh:5,
        timer:0,
        latest:0
    },params);
 
    var add_log = function(text){
        $('#for_ajax').prepend("<p>" + text + "</p>");
    };
 
    var format_date = function(d){
        var yyyy = d.getFullYear();
        var mm = '0' + (d.getMonth() + 1);
        var dd = '0' + d.getDate();
        var hh = '0' + d.getHours();
        var nn = '0' + d.getMinutes();
        var ss = '0' + d.getSeconds();
        return yyyy
            + '/' + mm.slice(-2)
            + '/' + dd.slice(-2)
            + ' ' + hh.slice(-2)
            + ':' + nn.slice(-2)
            + ':' + ss.slice(-2);
    };
 
    var reload_json = function(){
        $.getJSON(
            "<%= url_for 'json' %>",
            { 'from_id':params.latest },
            function(json) {
                $.each(json, function(i, val){
                    params.latest = val.id;
                    var latest = new Date();
                    latest.setTime(val.ts * 1000);
                    add_log(val.id + ". " + val.msg + " <small>" + format_date(latest) + "</small>");
                });
                clearTimeout(params.timer);// 念のためタイマーをリセット
                params.timer = setTimeout(reload_json,params.refresh*1000);// 次回の実行はparams.refresh秒後
            }
        );
    };
    params.timer = setTimeout(reload_json,0);// 一回目実行
 
    $("#msg_form").submit(function() {
        if ( 0 < $("#message").val().length ) {
            $.post("<%= url_for 'json' %>", {
                'msg':$("#message").val(),
            },
            function(json) {
            }, 'json');
            $("#message").val('');
        }
        return false;
    })
});
% end
<div>
<%= form_for '/' => (method => 'post', id => 'msg_form') => begin %>
  <%= text_field 'msg' => (id => 'message') %>
  <%= submit_button '発言する' %>
<% end %>
</div>
<div id="for_ajax"></div>
 
@@ layouts/main.html.ep
<!DOCTYPE html>
<html>
  <head>
    <meta charset="<%= app->renderer->encoding %>">
    <title>Mojolicious</title>
    %= javascript 'https://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'
  </head>
  <body><%= content %></body>
</html>

トラックバック(2)

このブログ記事に対するトラックバックURL:

このブログ記事を参照しているブログ一覧:

日曜プログラマのそゞろ事 - Data::Modelで$row->get_columnsを覚えた (2011年1月11日 20:43)

JSONを返すスクリプトの記事で、リストを作るときに以下のようにしていたのですが... 続きを読む

色々と駆使して今更チャットを作ってみたわけですが、適当に追加していると、本当に追... 続きを読む

Google検索

Last.fm

このブログ記事について

このページは、nqounetが2011年1月10日 01:43に書いたブログ記事です。

ひとつ前のブログ記事は「ORLiteを日本語に対応させるテクニック」です。

次のブログ記事は「Data::Modelで$row->get_columnsを覚えた」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Creative Commons License
このブログのライセンスは クリエイティブ・コモンズライセンス.
Powered by Movable Type