FAQ
many-to-many interface SOLVED:

Here's how we do the many-to-many interface, made brain-dead simple thanks
to Moose, DBIC and FormHandler. All the heavy lifting is handled backstage,
we don't need to lift a finger. We thought we'd have to do lots of
mechanical drudgery, but it's all handled for me!

Here's the relationship-definition between the main record (incident) and
two of its linking tables (one for agencies, one for contractors):

package *Spill::Schema::DB::Result::Incident*;
#...
__PACKAGE__->has_many( map_incident_agency =>
'Spill::Schema::DB::Result::IncidentAgency' => 'incident' );
__PACKAGE__->many_to_many( *agencies* => 'map_incident_agency',
'agency' );

__PACKAGE__->has_many( map_incident_contractor =>
'Spill::Schema::DB::Result::IncidentContractor' => 'incident' );
__PACKAGE__->many_to_many( *contractors* => 'map_incident_contractor',
'contractor' );

meanwhile in the form...

package *Spill::Form::IncidentForm*;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';

has '+item_class' => ( default => 'Incident' ); # ties it to DBIC
#...
has_field '*agencies*' => ( type => 'Multiple' );
has_field '*contractors*' => ( type => 'Multiple' );

then in the controller...

package Spill::Controller::Spill;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
#...
has '*form*' => (
isa => 'Spill::Form::IncidentForm',
is => 'rw',
lazy => 1,
default => sub { Spill::Form::IncidentForm->new },
);
#...
sub my_action : Action {
#..
my $form = $c->*form*;
my $obj = $c->model('blah')->find_or_new({id=>$id});
return unless process( # *MAGIC!*
item => $obj, # take this database object
params => $c->req->params, # and update it if everything validates
);
#..
}

With those definitions in place, your [% form.render %] (or [%
form.render_field('agencies') %] if you're hand-rolling your form) will do
the right thing, no problem!

If you need to filter the items that populate the multi-select list, no
problem. There's another link between incident and, this time, person --
only we want to limit the person-list to just those related to the "org" in
the incident itself:

# back in package *Spill::Form::IncidentForm*
sub options_persons {
my $self = shift;
return unless $self->schema;

my $persons = $self->schema->resultset('Person');
my $org = $self->field('org')->init_value;
$persons = $persons->search(
{ $org ? (org => $org) : () },
{order_by => ['lname','fname']},
);
my @persons;
while ( my $person = $persons->next ) {
push @persons, {
value => $person->id,
label => $person->name,
#active => $person->active,
};
}
return \@persons;
}

The active label seems to be ignored when we do this, unfortunately. And
really we should pull "org" from $c->user instead of the form.

But whether you roll your own list or let FormHandler/DBIC pull them all --
in your browser you get a multi-select list of all the items in each
many-to-many relationship, and users can click to turn them on or off. Click
"submit", and the linking-table gets updated accordingly. Very, very nice!

Catalyst, DBIx::Class, HTML::FormHandler, Moose -- woo hoo! Kudos, big fat
thumbs up!


--
Failure is not important. How you overcome it, is.
-- Nick Vujicic
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20101125/857f62d5/attachment.htm

Search Discussions

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedNov 25, '10 at 10:36p
activeNov 25, '10 at 10:36p
posts1
users1
websitecatalystframework.org
irc#catalyst

1 user in discussion

Will Trillich: 1 post

People

Translate

site design / logo © 2022 Grokbase