Mojolicious::LiteでData::Modelを使ってみたという記事で、
MojoliciousのWikiにORLiteを使ったサンプルがあったのですが、残念ながらそのままでは日本語には対応していないので、…
という文を見かけたので、その Working with ORLite inside Mojolicious にあるサンプルを日本語でも使えるようにできないか、調べてみました。
Mojolicious::Liteにおける文字エンコーディング周りの動作を調べてみたところ、Mojolicious::Liteの内部では、文字列はあくまでPerlの内部文字列として扱われることを知りました。具体的に言うと:
なので、 $self->param('type') のようにして取得したデータは、その時点で内部文字列となっているし、また、データベースから取得したデータをテンプレートに埋め込むならば、内部文字列とした上で埋め込む必要がある、ということになります。
そうすると修正はデータベース寄りということになりそうです。調べると、ORLiteが使用するDBD::SQLiteには、入出力データを内部文字列として扱うための属性(sqlite_unicode)がありました。しかしORLiteではその属性を使用していないようです。
そこで、以下のように package Model のところで connect メソッドを上書きすることで、日本語文字列のポスト・表示にも対応することができました。
追記(2012年2月3日): ORLite がバージョン1.52以降で unicode
オプションをサポートしたため、以下のソースも変更しました。
#!/usr/bin/env perl
package Model;
use strict;
use ORLite {
file => 'sample.db',
create => sub {
my $dbh = shift;
$dbh->do(
'CREATE TABLE motorcycles (
id INTEGER PRIMARY KEY,
type TEXT NOT NULL,
brand TEXT NOT NULL,
color TEXT)'
);
# just use $dbh->do(...) if you need more
# tables
return 1;
},
# ORLite >= 1.52
unicode => 1,
};
#{
# # use unicode character (ORLite < 1.52)
# my $connect = sub {
# DBI->connect( $_[0]->dsn, undef, undef, {
# PrintError => 0,
# RaiseError => 1,
# sqlite_unicode => 1,
# } );
# };
# no warnings 'redefine';
# *connect = $connect;
#}
package main;
use Mojolicious::Lite;
use utf8;
get '/' => sub {
my $self = shift;
$self->stash(motorbikes => [Model::Motorcycles->select('order by type')]);
} => 'index';
post '/' => sub {
my $self = shift;
Model::Motorcycles->create(
type => $self->param('type'),
brand => $self->param('brand'),
color => $self->param('color')
);
$self->redirect_to('/');
};
app->start;
__DATA__
@@ index.html.ep
<!DOCTYPE html>
<html>
<head>
<title>Motorcycles</title>
<style>td { background-color:#dee; } </style>
</head>
<body>
<h1>Motorcycles</h1>
<table>
% foreach my $cycle (@{$motorbikes} ) {
<tr>
<td><%= $cycle->type %></td>
<td><%= $cycle->brand %></td>
<td><%= $cycle->color %></td>
</tr>
% }
</table>
<p>Enter a new motorcycle here (バイクを登録して下さい)</p>
<p>
<%= form_for '/' => (method => 'post') => begin %>
% foreach (qw/type brand color/) {
<%= uc($_) %>: <%= input_tag $_, 'type' => 'text' %><br />
% }
<%= submit_button 'Submit motorcycle' %>
<% end %>
</p>
</body>
</html>
スクリプト内部(__DATA__ 以下)のテンプレートで日本語文字列を使うような場合は、内部文字列として扱われるように use utf8; を追加しておくとよさそうです。