Mojoliciousが1.01になりましたね。 まあ、それとは関係ないですが、jQueryを使ってAJAXなチャットを作ってみたので晒してみようかと思います。 AJAX自体、やった事が無いので、もっと良いやり方があるとは思います。 値の受け渡しはJSONを使ったのですが、Mojolicious側の受け取り方法がよく分からなくて$self->req->jsonとか、Mojo::JSON->newとかやっていたのですが、結果的に普通に$self->paramで受け取れるのがわかって、凄いと思いました。 JavaScript側では、Perlからのtime値をどうやって渡すのかが、調べていてもよく分からなかったので、正解に行き着くのが大変でした。 ミリセカンドで渡す、というのは気づきませんでした。 常識すぎてあまり書かれないんでしょうか…。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/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>