[Dbix-class] Unable to call result class method...

Amiri Barksdale amiri at metalabel.com
Sun Mar 28 20:37:44 GMT 2010


I am having a weird problem, I think with relationships, but I don't
know what's wrong. I have two schema classes: the document belongs to
the template, and the template has many documents. The template has a
subroutine that is supposed to do some stuff for me in a controller
later. But I cannot call it as expected:
$document->template->document_class. I can call it if I find the
template first, e.g., $c->model('DB::Template')->find({ id => $id }),
and then do $template->document_class.

Here's the template class:

   package W::S::R::Template;

   ...

   __PACKAGE__->table("template");
   __PACKAGE__->add_columns(
       "id",
       {   data_type         => "integer",
           default_value     => \"nextval('template_id_seq')",
           is_auto_increment => 1,
           is_nullable       => 0,
       },
       "name",
       { data_type => "text", default_value => undef, is_nullable => 0 },
   );
   __PACKAGE__->set_primary_key("id");
   __PACKAGE__->has_many(
       "documents",
       "W::S::R::Document",
       { "foreign.template_id" => "self.id" },
       { cascade_delete     => 1 },
   );

   ...

   sub document_class {
       #print STDERR @_;
       my ( $self, $template_id ) = @_;
       switch ($template_id) {
           case 1 {
               return
   $self->result_source->schema
   ->resultset('WillNoChildren')->find( { id => 1 } );
           }
           case 2 {
               return
   $self->result_source->schema
   ->resultset('StatutoryPowerAttorney')->find( { id => 1 } );
           }
           case 3 {
               return
   $self->result_source->schema
   ->resultset('StatutoryPowerAttorney')->find( { id => 1 } );
           }
       }
   }

   1;

Here's the document class:

   package W::S::R::Document;

   use Moose;
   extends 'W::S::R';
   use Warner::Types::Library qw/:all/;
   use namespace::autoclean;

   __PACKAGE__->table("document");
   __PACKAGE__->add_columns(
   ...
     "template_id",
     {
       data_type      => "integer",
       default_value  => undef,
       is_foreign_key => 1,
       is_nullable    => 0,
     },
   ...
   );
   __PACKAGE__->set_primary_key("id");

   __PACKAGE__->belongs_to(
     "template",
     "W::S::R::Template",
     { "foreign.id" => "self.template_id" },
     { cascade_delete => 1 },
   );
   ...

   1;


In a controller:

   sub index : Chained('base') : PathPart('') Args(0) {
       my ( $self, $c ) = @_;
       my $document = $c->session->{document};
       my $template = $c->model('DB::Template')->find({ id =>
   $document->template_id });
       $c->log->debug(ref $template); ## OK
       $c->log->debug($document->template_id); ## OK
       $c->log->debug($document->template->document_class); 
   ...
   }

That last line throws the error:

   Caught exception in Warner::Web::Controller::Checkout->index "Can't call
   method "select_single" on an undefined value at
   /home/amiri/warner/lib/perl5/DBIx/Class/ResultSet.pm line 750."

These tests all pass:

   ok(my $document = $schema->resultset('Document')->new_result({
   template_id => 1, user => 1 }), 'created new will_no_children document
   OK');
   is(ref $document->template, 'W::S::R::Template',
   'documents template accessor delivers proper type');
   is($document->template_id, '1', 'documents template id is correct');

   is(ref $document->template->document_class($document->template_id),
   'W::S::R::WillNoChildren', 'document_class sub returns
   proper object');


I wrote another set of tests that finds a document and then calls
$document->template methods, and that works too.

Amiri



More information about the DBIx-Class mailing list