DBIx::Class + Catalyst::View::JSON

InflateColumnを使っているときに問題があったため、修正版を新しいエントリに起こしました。
修正版:DBIx::Class + Catalyst::View::JSON(2) - ヒルズで働く@robarioの技ログ



昔書いたメモが出てきたので転載。

DBIC::ResultSet#findやDBIC::ResultSet#searchしたものをそのままJSONにしたいじゃないですか。
でもCatalyst::View::JSONにそのまま渡すとCatalystが落ちるんですよ。
なので適当に展開してくれるサブルーチンを作って使っています。
Catalyst::View::JSON以外でも使うので、アプリケーションクラスに置いています。

### lib/MyApp.pm
sub expand_dbic {
    my ( $c, $obj ) = @_;

    if ( !Scalar::Util::blessed($obj) ) {
        return $obj;
    }

    if ( $obj->isa('DBIx::Class::Row') ) {
        return { $obj->get_columns };
    }
    if ( $obj->isa('DBIx::Class::ResultSet') ) {
        return [ map { +{ $_->get_columns } } $obj->all ];
    }

    return $obj;
}

### lib/MyApp/View/JSON.pm
package MyApp::View::JSON;
use base qw(Catalyst::View::JSON);
sub process {
    my ( $self, $c ) = @_;
    $c->stash->{response} = $c->expand_dbic( $c->stash->{response} || {} );
    $self->SUPER::process($c);
}

使用例

### /lib/MyApp/Controller/Root.pm
sub default : Path {
    my ( $self, $c ) = @_;
    $c->stash->{response} = $c->model('DBIC')->resultset('Example')->find(...);
}

sub index : Private {
    my ( $self, $c ) = @_;
    $c->stash->{response} = $c->model('DBIC')->resultset('Example')->search(...);
}

sub end : Private {
    my ( $self, $c ) = @_;
    $c->forward($c->view('JSON'));
}