3

I am using Catalyst Perl MVC framework with HTML::FormHandler as forms processor.

Are there any ways to create multiple objects and save them into appropriate separate tables using single form?

romel
  • 97
  • 5
  • I have looked for such general solution for other frameforks and form generators too but have not found any solution for now. – w.k Aug 28 '12 at 11:07

2 Answers2

3

After some time was spent reading the documentation and finally IRC help I figured out how to do it. It's quite simple.

Let's say we have 2 related tables: 'account' and 'user'. And 'account' hasMany 'users', with this relationship being called 'users'.

The code in controller Account.pm stays the same (remember we are using HTML::FormHandler to process the form and create new objects):

sub register : Chained('base') :PathPart('register') :Args(0) {
    my ($self, $c ) = @_;
    my $account = $c->model('DB::Account')->new_result({});
    return $self->form_create($c, $account);
}
sub form_create {
    my ( $self, $c, $account ) = @_;
    my $form = MyApp::Form::Account->new();
    $c->stash( template => 'account/form.tt2', form => $form );
    $form->process( item => $account, params => $c->req->params );
    return unless $form->validated;
}

All we do is use http://metacpan.org/pod/HTML::FormHandler::Field::Repeatable like that in our lib/MyApp/Form/Account.pm:

package MyApp::Form::Account;

use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
use namespace::autoclean;

has '+item_class' => ( default => 'Account' );
has_field 'organization';
# other fields ...

# User Part Form
has_field 'users' => ( type => 'Repeatable' ); # 'users' is our relationship name!
has_field 'users.first';
has_field 'users.last';
# and so on...
has_field 'submit' => ( type => 'Submit', value => 'Submit' );
__PACKAGE__->meta->make_immutable;
1;

After submitting we get freshly created 'account' and 'user' objects, where 'user' already has corresponding 'account_id' inserted :)

szabgab
  • 6,202
  • 11
  • 50
  • 64
kK-Storm
  • 474
  • 1
  • 4
  • 16
1
  1. Form submits
  2. Params are validated

    $form->process()

  3. Data is inserted into tables as appropriate.

    $rec = $c->model(table_1)->create(valid_data);
    $rec->create_related('relationship_name', related_data);

I am unaware of a method for having DBIC perform both inserts automatically. But that isn't to say that one doesn't exist. I just didn't see anything in the FormHandler::DBIC documentation.

Len Jaffe
  • 3,442
  • 1
  • 21
  • 28
  • Can you elaborate? Best would be with simple example. It could be quite obvious to somewhat experienced coder, but I'm also a newcomer and already spent few hours trying to figure out how to do this, nothing works :( – kK-Storm Aug 28 '12 at 21:54
  • how would you do this if it were one form, and one table? – Len Jaffe Aug 28 '12 at 22:16
  • There's a huge, wonderful catalyst tutorial. I'm not going to reproduce it here. Once you figure out how to insert data into one table, writing a second insert is trivial. – Len Jaffe Aug 28 '12 at 22:28
  • I still need more info: the nature of the two table you want to insert into...are they related? is there repeating data on the form? are y ou using DBIC with Catalyst and FormHandler? – Len Jaffe Aug 28 '12 at 22:38
  • Yes, I'm using DBIC with Catalyst and FormHandler. There isn't any repeating data on the form (all columns have different names). Tables are related, one is 'account' and second is 'user'; account hasMany users (column account_id in 'user' table is present). – kK-Storm Aug 28 '12 at 22:47
  • @LenJaffe: which Catalyst tutorial you are reffering? – w.k Aug 30 '12 at 12:39