天然パーマです。

MojoliciousでRails風のRESTディスパッチ

GET、POST、PUT、DELETEの4つのメソッドを使い切ってリソースをコントロールしようというRESTfulな概念には賛同だけれども、 ブラウザがGET、POSTのみのサポートだよねぇ〜っていう状況はよくあります。 Ruby on Railsではそこまで深く調べてないけど、POSTメソッドのパラメータ「_method」に「DELETE」か「PUT」という値を入れることでもう二つのメソッドをサポートさせているように見せている?ようだ。

Perlで僕がいつも使っているWAF、MojoliciousではサーバサイドのルータでPUT、DELETEに対応しているので、 Railsで使っている「_method」フィールドを活用すればそれなりにRESTfulでありコントローラの記述も スッキリするんじゃないかと思う。 つまりディスパッチ前にうまいことフックさせて_methodの値でメソッドを書き換える。

よって以下のMojolicious::Liteのコードがうまく動いた。

#!/usr/bin/env perl
use Mojolicious::Lite;

app->hook(
    before_dispatch => sub {
        my $c = shift;
        if($c->req->method eq 'POST' && $c->req->param('_method')) {
            my $methods = [qw/GET POST PUT DELETE/];
            if ( grep { $_ eq $c->req->param('_method') } @$methods ) {
                $c->req->method( $c->req->param('_method') );
            }
        }
    }
);

get '/' => sub {
    my $self = shift;
    $self->render('index');
};

del '/' => sub {
    my $self = shift;
    $self->render_text('DELETE resource!');
};

app->start;

__DATA__

@@ index.html.ep
<form action="/" method="post">
   <input type="hidden" name="_method" value="DELETE" />
   <input type="submit" value="DELETE" />
</form>

ふむ、なかなかよさげです。とあるプロジェクトのコードで試してみるとします。