2 nice techniques to refactor Mojolicious controllers
Let's start with this ugly piece of code.
sub grow {
my ($self) = @_;
my $moustache = $self->app->moustaches->create({});
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $moustache->id );
}
sub show {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$self->stash( moustache => $moustache );
}
sub trim {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$moustache->delete;
$self->res->code(204);
}
The first nice refactoring we can do here is to define an attribute with a lazy builder callback.
has 'moustache' => sub {
my ($self) = @_;
return $self->app->moustaches->find( $self->param('id') );
};
sub grow {
my ($self) = @_;
$self->moustache( $self->app->moustaches->create({}) );
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $self->moustache->id );
}
sub show {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->stash( moustache => $self->moustache );
}
sub trim {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->moustache->delete;
$self->res->code(204);
}
The next obvious candidate for refactoring is the existence check, but there's no analogue of Rails' before_filter
in Mojolious. Fortunately there's a nice module Class::Method::Modifiers
, which is used in Moo
, by the way.
use Class::Method::Modifiers;
has 'moustache' => sub {
my ($self) = @_;
return $self->app->moustaches->find( $self->param('id') );
};
around [ qw{ show trim shave } ] => \&_assert_moustache;
sub grow {
my ($self) = @_;
$self->moustache( $self->app->moustaches->create({}) );
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $self->moustache->id );
}
sub show {
my ($self) = @_;
$self->stash( moustache => $self->moustache );
}
sub trim {
my ($self) = @_;
$self->moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
$self->moustache->delete;
$self->res->code(204);
}
sub _assert_moustache {
my $orig = shift;
my $self = shift;
if ( !$self->moustache ) {
$self->render_not_found;
}
return $orig->($self);
}
Note, that in order to make it possible to prevent execution of the method, that we apply a filter to, we need to use around
, because before
doesn't allow it.
Written by Ivan Fomichev
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Perl
Authors
janosgyerik
25.11K
Jean-Remy Duboc
12.22K
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#