<div>many-to-many interface SOLVED:</div><div><br></div><div>Here&#39;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&#39;t need to lift a finger. We thought we&#39;d have to do lots of mechanical drudgery, but it&#39;s all handled for me!</div>
<div><br></div><div>Here&#39;s the relationship-definition between the main record (incident) and two of its linking tables (one for agencies, one for contractors):</div><div><br></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">package <b>Spill::Schema::DB::Result::Incident</b>;<br>
#...<br>__PACKAGE__-&gt;has_many( map_incident_agency     =&gt; &#39;Spill::Schema::DB::Result::IncidentAgency&#39;     =&gt; &#39;incident&#39; );<br>__PACKAGE__-&gt;many_to_many( <b>agencies</b>     =&gt; &#39;map_incident_agency&#39;,     &#39;agency&#39; );<br>
<meta charset="utf-8"><br></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">__PACKAGE__-&gt;has_many( map_incident_contractor     =&gt; &#39;Spill::Schema::DB::Result::IncidentContractor&#39;     =&gt; &#39;incident&#39; );<br>
__PACKAGE__-&gt;many_to_many( <b>contractors</b>  =&gt; &#39;map_incident_contractor&#39;, &#39;contractor&#39; );<br></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><meta charset="utf-8"><span class="Apple-style-span" style="font-family: arial; "><div>meanwhile in the form...</div><div><br></div></span></font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">package <b>Spill::Form::IncidentForm</b>;<br>use HTML::FormHandler::Moose;<br>extends &#39;HTML::FormHandler::Model::DBIC&#39;;</font></div><div>
<font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><div><br></div><div>has &#39;+item_class&#39; =&gt; ( default =&gt; &#39;Incident&#39; ); # ties it to DBIC</div>#...<br>has_field &#39;<b>agencies</b>&#39;    =&gt; ( type =&gt; &#39;Multiple&#39; );<br>
has_field &#39;<b>contractors</b>&#39; =&gt; ( type =&gt; &#39;Multiple&#39; ); <br></font><br></div><div><meta charset="utf-8"><div>then in the controller...</div></div><div><br></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">package Spill::Controller::Spill;</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">use Moose;</font></div></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">use namespace::autoclean;</font></div><div>
<font class="Apple-style-span" face="&#39;courier new&#39;, monospace">BEGIN { extends &#39;Catalyst::Controller&#39;; }</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">#...</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">has &#39;<b>form</b>&#39; =&gt; (</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    isa     =&gt; &#39;Spill::Form::IncidentForm&#39;,</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    is      =&gt; &#39;rw&#39;,</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    lazy    =&gt; 1,</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    default =&gt; sub { Spill::Form::IncidentForm-&gt;new },</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">);</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">#...</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">sub my_action : Action {</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  #..</font></div>
<meta charset="utf-8"><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  my $form = $c-&gt;<b>form</b>;</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  my $obj  = $c-&gt;model(&#39;blah&#39;)-&gt;find_or_new({id=&gt;$id});</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  return unless process( # <b><u>MAGIC!</u></b></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    item   =&gt; $obj,             # take this database object</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    params =&gt; $c-&gt;req-&gt;params,  # and update it if everything validates</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  );</font></div>
<meta charset="utf-8"><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace; ">  #..</span></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">}</font></div>
<div><br></div><div>With those definitions in place, your <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">[% form.render %]</font> (or <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">[% form.render_field(&#39;agencies&#39;) %]</font> if you&#39;re hand-rolling your form) will do the right thing, no problem!</div>
<div><br></div><div>If you need to filter the items that populate the multi-select list, no problem. There&#39;s another link between incident and, this time, person -- only we want to limit the person-list to just those related to the &quot;org&quot; in the incident itself:</div>
<div><br></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"># back in </font><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace; ">package <b>Spill::Form::IncidentForm</b></span></div>
<meta charset="utf-8"><div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">sub options_persons {</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    my $self = shift;</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    return unless $self-&gt;schema;</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div><div>
<font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    my $persons = $self-&gt;schema-&gt;resultset(&#39;Person&#39;);</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"></font><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    my $org = $self-&gt;field(&#39;org&#39;)-&gt;init_value;</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    $persons = $persons-&gt;search(</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">        { $org ? (org =&gt; $org) : () },</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">        {order_by =&gt; [&#39;lname&#39;,&#39;fname&#39;]},</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    );  </font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    my @persons;</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    while ( my $person = $persons-&gt;next ) { </font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">        push @persons, {</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">            value =&gt; $person-&gt;id,</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">            label =&gt; $person-&gt;name,</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">            #active =&gt; $person-&gt;active,</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">        };  </font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    }   </font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    return \@persons;</font></div>
<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">}   </font></div></div><div><br></div><div>The active label seems to be ignored when we do this, unfortunately. And really we should pull &quot;org&quot; from $c-&gt;user instead of the form.</div>
<div><div><div><div class="gmail_quote"><div><br></div><div>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 &quot;submit&quot;, and the linking-table gets updated accordingly. Very, very nice!</div>
</div></div><div><br></div><div>Catalyst, DBIx::Class, HTML::FormHandler, Moose -- woo hoo! Kudos, big fat thumbs up!</div><div><br></div><div><br>-- <br>Failure is not important. How you overcome it, is.<br>-- Nick Vujicic<br>

</div></div></div></div></div>