Mojolicious でアプリケーションをつくってみた ②
の続きです。
モデル
アソシエーション
lib/MojoSample/Schema/Result/
以下にファイルを作成し、そこに記述します。
たとえば、memos の場合、アソシエーションは
belongs_to => user has_many => memo_tags many_to_many => tags
という感じです。その場合は以下のように記述します。
__PACKAGE__->belongs_to( user => 'MojoSample::Schema::Result::User', 'user_id' ); __PACKAGE__->has_many( memo_tags => 'MojoSample::Schema::Result::MemoTag', 'memo_id' ); __PACKAGE__->many_to_many( tags => 'memo_tags' => 'tag' );
キーになってる user
, memo_tags
, tags
はその名前でモデルからアクセスできるようになります。
例えば、
my $memo = $c->db->resultset('Memo')->search({id => $c->param('id')})->first(); print $memo->user->username;
という感じ。
値はアソシエーションするテーブルのResultクラス。
第二引数は外部キー。
many_to_many の場合のみ違うので注意が必要です。
ロジック
このResultクラスにメソッドを定義して、そのオブジェクトから呼び出すことが可能です。 例えば、以下はmemo に紐付いた複数のタグをカンマ区切りに出力する例ですが、
sub tag_str { my $self = shift; my $tag_str = ''; foreach $tag ($self->tags) { $tag_str .= $tag->name . ','; } chop($tag_str); return $tag_str; }
と定義して、
my $memo = $c->db->resultset('Memo')->search({id => $c->param('id')})->first(); print $memo->tag_str;
という感じで呼びだすことができます。
バリデーション
ここは一番苦労しました。 最初は Result クラスに
__PACKAGE__->validation( module => 'FormValidator::Simple', profile => [ title => ['NOT_BLANK'], content => ['NOT_BLANK'], ], filter => 0, auto => 1, );
みたいに書いていたんだけど、 入力された値がユニークかどうかチェックするやつがデフォルトになかったので、
FormValidator::Simple::Plugin::DBIC::Unique
というプラグインをつかうことにしました。
上記にある例にならって、
['DBIC_UNIQUE', 'MojoSample::Schema::Result::User', 'username']
としたんだけど全く動かない。 以下のようにresult set のオブジェクトを渡したら動きました。
['DBIC_UNIQUE', $schema->resultset('User'), 'username']
ただ、result set のオブジェクトを渡す場合、Resultクラスには書けないぽい。
$schema
が作られるのが Resultクラスの読み込みより後っぽいので。
なので lib/Mojosample.pm
に書くことにしました。
バリデーションエラーのメッセージもlib/Mojosample.pm
に書いています。
以下の感じです。
# Validation FormValidator::Simple->set_message_decode_from('utf-8'); FormValidator::Simple->set_messages({ users => { username => { NOT_BLANK => 'ユーザー名は必須です。', LENGTH => 'ユーザー名は4文字以上16文字以内で入力してください。', DBIC_UNIQUE => '指定されたユーザー名は既に使用されています。' }, password => { NOT_BLANK => 'パスワードは必須です。', LENGTH => 'パスワードは8文字以上16文字以内で入力してください。' } }, memos => { title => { NOT_BLANK => 'タイトルは必須です。', }, content => { NOT_BLANK => '内容は必須です。', } }, });
コントローラ
lib/MojoSample/Controller/
以下に定義します。
sub index { my $c = shift; my $memos = $c->db->resultset('Memo')->list($c->session->{login_user_id})->page(($c->param('page') || 1)); my $pager = $memos->pager(); $c->render(memos => $memos, pager => $pager); }
View への値受け渡しは
$c->render(memos => $memos, pager => $pager);
または
$c->stash(memos => $memos, pager => $pager);
とします。
セッションを用いたフラッシュメッセージは
$c->flash(message => 'メモを追加しました');
というようにします。
この辺の、mojolicious 単体については
https://github.com/yuki-kimoto/mojolicious-guides-japanese/wiki
に詳しくかいてあります。僕が紹介するまでもないって感じです。^^;
ルーティング
まず、コード載せます。
# Router my $r = $self->routes; # Normal route to controller my $filter = $r->under->to('Base#before_filter'); $filter->get('/')->to('Top#index'); $filter->get('/users/login')->to('Users#login'); $filter->post('/users/login')->to('Users#login'); $filter->get('/users/new')->to('Users#new_'); # new は使えなかった $filter->post('/users/create')->to('Users#create'); # ログインが必要になるページ my $login_required = $filter->under->to('Users#logined_check'); $login_required->get('/memos')->to('Memos#index'); $login_required->get('/memos/new')->to('Memos#new_'); # new は使えなかった $login_required->get('/memos/:id/show')->to('Memos#show'); $login_required->post('/memos/create')->to('Memos#create'); $login_required->post('/memos/:id/destroy')->to('Memos#destroy'); $login_required->get('/memos/:id/edit')->to('Memos#edit'); $login_required->post('/memos/:id/update')->to('Memos#update'); $login_required->get('/users/logout')->to('Users#logout');
ログインが必要になる箇所とそうでない箇所で分けて書いてあります。
何かしらのアクションに行く前に Base
コントローラの before_filter
を通っています。
そこでログインしているユーザーのオブジェクトをセットしています。
Memos
コントローラは全てログインが必要なので、
my $login_required = $filter->under->to('Users#logined_check');
として、
Users
コントローラの logined_check
アクションを噛ませます。
そこでログイン状態をみてログインしてなかったらログインページにリダイレクトさせれば良さそうです。