dariusj has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I'm trying to run a method on a DBIx object in a template through Template Toolkit - the same method works when written in perl directly.

<input type="text" size="3" name="measure-[% variant.id %]-[% type_measurement.measurement_id +%]" value="[% variant.variant_measurements.find(variant.id, type_measu +rement.measurement_id).value %]"/>
Where:
variant.id displays correctly as 83398
type_measurement.measurement_id displays correctly as 3
These values entered into the DBIx find method should return a row_object, that has a column value, and this works correctly when in perl - whereas in the template I am getting nothing - any help?

Thanks.

Replies are listed 'Best First'.
Re: Methods in template toolkit
by stvn (Monsignor) on Dec 06, 2007 at 13:55 UTC

    Without knowing more details about what DBIx:: module you are using I cannot say for sure, however I suspect that the issue you are seeing here is related to return context. Your find method maybe returns one thing in scalar context (a row_object) and another thing in list context? If that is the case TT might be calling it in list context in this case. I know I have been bitten by similar things while using TT and DBIx::Class. In general being very explicit in TT code is the best option.

    -stvn
      stvn: you were right! I was looking at the wrong method - I should have been looking at variant_measurements (a has_many relationship) that can return both a scalar and a list - adding _rs on the end forces it to return a scalar.

      So, the working code is variant.variant_measurements_rs.find(variant.id, type_measurement.measurement_id).value

      Cheers!

      Thanks for your reply, actually the find method I'm using is documented here, if I'm reading the docs correctly it should only return a scalar.

      I'm trying to find a workaround for this problem, but this would be the simplest and neatest way to do it, and I don't understand why it's not working... (frustration sets in)!

      Should probably add that the primary key is a compound key made up of ($variant_id, $measurement_id)
Re: Methods in template toolkit
by moritz (Cardinal) on Dec 06, 2007 at 16:10 UTC
    Just a matter of style: I don't think it's a good idea to do database lookups in the templates.

    That's what the controller (in an MVC approach; the calling script otherwise) is for.

    You use a template system because you want to separate program logic and layout - but database calls are surely not a layout technique.

      I disagree (partially), what the OP is doing here is just grabbing a related object, which is not much different from grabbing a value from a local field. I do agree that the code to fetch from the resultset and such should probably not be in the View, but I would probably put this into the Model rather then the Controller, something like this in his Variant class would work.

      sub get_related_measurement_thingy { my ($self, $type_measurement) = @_; $self->variant_measurements_rs->find( $self->id, $type_measurement->measurement_id ); # the template should probably call ->value though }
      then the OP could improve on it and add error handling or additional validation as well.

      -stvn
        I have actually changed the implementation of this - the call was going through a loop, filling table data cells - many database calls. I now have this:
        sub get_variant_measurements { my $resultset = shift; my $variant_id = @_; my $variant_measurements = $resultset->search_related( 'variant_measurements', { }, { 'order_by' => ['variant_id','measurement_id'] }, ); return $variant_measurements; }
        This is passed to the template, which then does this:
        [% WHILE ( type_measurement = type_measurements.next ) %] <tr> [% WHILE (variant_measurement = variant_measurements.next) %] [% IF variant_measurement.measurement_id == type_measurement.measure +ment_id %] <td> <input type="text" size="3" name="measure-[% variant_measurement.variant_id %]-[% typ +e_measurement.measurement.measurement %]" value="[% variant_measurement.value %]" /> </td> [% END %] [% END %] </tr> [% END %]
        Little hard to work out from the current context, what the db calls done previously in a loop in the template are now carried out in one database call in the handler.