[Catalyst] Best practices: XML output from static XML

J. Shirley jshirley at gmail.com
Sat Mar 6 20:59:38 GMT 2010


On Sat, Mar 6, 2010 at 8:25 AM, Bill Moseley <moseley at hank.org> wrote:
>
>
> On Sat, Mar 6, 2010 at 6:34 AM, J. Shirley <jshirley at gmail.com> wrote:
>>
>> > Just one last question. When you talk about using
>> > 'lib/MyApp/View/MyView.pm', you mean that is also correct to create a
>> > simple
>> > perl Module for your view. Then implement process method in the View.pm
>> > and
>> > forward the context from the Controller ( $c->forward(
>> > $c->view('MyView') );
>> > )?
>> >
>> >
>> > David
>> >
>>
>> Yup, that is exactly right.
>
> Expanding this thread a bit...
> I asked a related question in another thread.  What if you want a view that
> needs separate code for each action?
> For example, when no template is explicitly defined in the action,
> C::View::TT will pass control to a template based on the action's name.
>  Each action can have its own associated template.
> Likewise, for a different type of output I might need code to run for each
> action.
> Say the controller action for the path /music/recent_uploads places a list
> of objects in the stash.  Rendering with HTML sends it to TT (e.g
> /templates/music/recent_uploads.tt).  But, what if the client wants, say an
> RSS feed or JSON response for that same action?  Doesn't that seems like a
> View's job to turn that into a feed or JSON?
> But for both of those examples I need code to serialize those objects in the
> stash (into a feed or JSON).  So, my question is 1) how to map the action
> into a view method, and 2) where those view methods should live?
> I don't think a separate view for every possible action is the correct
> approach.  Seems better to have in an end() method simply:
> $c->forward( $c->view( $view_type ) );
>
> A simplistic or naive View approach might look like:
> sub process {
>     my ( $self, $c ) = @_;
>     my $method = $c->action->reverse;
>     $method =~ s{/}{_};
>     $self->$method( $c ) if $self->can( $method );
> }
> But, that's flat and ugly.
> I could keep the "view" code in with the controllers which in some way makes
> maintenance easier (related code is together), but then the view is not
> separate.
> my $method = $c->action->name;
> $method .= '_render_json';
> $c->action->controller->$method( $c );
>
> So, what's the recommended approach to per-action view code?
>
>

I don't think the path taken with Catalyst::Action::REST is the best,
but it does work very very well in my opinion and I certainly can't
think of anything better.  Being able to send to a serialization
method based on the content-type solves a lot of these issues.  You
could just setup a content type for your feed in configuration and
write a custom serialize class and get exactly what you are asking
for.

I don't want to evangelize ::REST too much, so to address your
suggestions more directly I'd have to say that relying on $self->can
seems a bit too limited for my tastes.

I'd lean on configuration more so than $self->can.  Then a call to
$self->get_serializer_for('JSON') that returns some serialization
object (or whatever handler you have) is simple, and coupling it with
Moose would work very well.  Then you can work out adding new
serialization calls just in config.

However, I'm having a hard time thinking about any valid use cases for
this, especially since ::REST does things fairly well (especially for
how old the code is) so I'd automatically use that for all the cases I
can think of. Anything else that doesn't fit, I'd just defer to having
separate views (and possibly a different RenderView+end action as
appropriate).

-J



More information about the Catalyst mailing list