http://www.perlmonks.org?node_id=1020373

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

Hello Monks,

I am trying to figure out how to get HTML::FormHandler to update related rows in different tables. It seems to follow the many_to_many relationship without issue, but it does not seem to honor the has_one relationship.

The full code that I'm working with is here: https://github.com/three18ti/catalyst-app.git I'm currently working on the "profile-attempt2" branch

I have my User and Profile Classes:

package MyApp::Schema::Result::User; use Moose; use MooseX::NonMoose; use namespace::autoclean; use List::MoreUtils qw(any none); extends 'MyApp::Schema::Result'; __PACKAGE__->table('user'); __PACKAGE__->load_components( qw( EncodedColumn ) ); __PACKAGE__->add_columns( id => { data_type => 'integer', size => 16, is_nullable => 0, is_auto_increment => 1 }, username => { data_type => 'varchar', size => 256, is_nullable => 0, is_auto_increment => 0, }, ); __PACKAGE__->set_primary_key('id'); __PACKAGE__->has_one('profile' => 'MyApp::Schema::Result::Profile', 'u +ser_id'); __PACKAGE__->has_many( user_roles => 'MyApp::Schema::Result::UserRole' +, 'user_id' ); __PACKAGE__->many_to_many( roles => 'user_roles', 'role' );
package MyApp::Schema::Result::Profile; use Moose; use MooseX::NonMoose; use namespace::autoclean; extends 'MyApp::Schema::Result'; __PACKAGE__->table('profile'); __PACKAGE__->add_columns( user_id => { data_type => 'integer', size => 16, is_foreign_key => 1, is_nullable => 0, }, name => { data_type => 'varchar', size => 256, is_nullable => 0, is_auto_increment => 0, }, email => { data_type => 'varchar', size => 256, is_nullable => 0, is_auto_increment => 0, }, ); __PACKAGE__->set_primary_key('user_id'); __PACKAGE__->has_one('profile' => 'MyApp::Schema::Result::User', 'id') +; 1; __END__

Now, I am able to access the fields of the profile table via $user->profile->name or $user->profile->email, like in my database deploy script (can be found in scripts/myapp_loaddb.pl relevant pieces below)

#!/usr/bin/env perl use lib 'lib'; #use MyApp; use 5.014; use strict; use warnings; use MyApp::Schema; #my $schema = My->schema; my $schema = MyApp::Schema->connect( 'dbi:SQLite:db/myapp.db', ); $schema->deploy({ add_drop_table => 1}); $schema->resultset('User')->populate([ [ qw( id username password ) ], [1, 'test1', 'foo' ], [2, 'test2', 'bar' ], [3, 'test3', 'baz' ], [4, 'test4', 'stuff' ], [5, 'test5', 'stuff2' ], ]); $schema->resultset('Profile')->populate([ [ qw ( user_id name email ) ], [1, 'Test User 1', 'test1@example.org', ], [2, 'Test User 2', 'test2@example.org', ], [3, 'Test User 3', 'test3@example.org', ], [4, 'Test User 4', 'test4@example.org', ], [5, 'Test User 5', 'test5@example.org', ], ]); foreach my $user ($schema->resultset('User')->all) { $user->add_role('User'); } foreach my $user ($schema->resultset('User')->all) { say "Username: " . $user->username; say "Name: ". $user->profile->name; }

However, when I try to get HTML::FormHandler to process the related updates I get the following error:

DBIx::Class::Storage::BlockRunner::__ANON__(): No such column, relatio +nship, many-to-many helper accessor or generic accessor 'email' at /r +oot/perl5/lib/perl5/Context/Preserve.pm line 22 DBIx::Class::Storage::BlockRunner::__ANON__(): No such column, relatio +nship, many-to-many helper accessor or generic accessor 'name' at /ro +ot/perl5/lib/perl5/Context/Preserve.pm line 22 DBIx::Class::Storage::BlockRunner::__ANON__(): No such column, relatio +nship, many-to-many helper accessor or generic accessor 'profile.emai +l' at /root/perl5/lib/perl5/Context/Preserve.pm line 22 DBIx::Class::Storage::BlockRunner::__ANON__(): No such column, relatio +nship, many-to-many helper accessor or generic accessor 'profile.name +' at /root/perl5/lib/perl5/Context/Preserve.pm line 22

My form looks like this:

package MyApp::Form::User; use HTML::FormHandler::Moose; extends 'MyApp::Form::Base'; with 'HTML::FormHandler::Widget::Theme::Bootstrap'; =head1 NAME Form object for the User Controller =head1 SYNOPSIS Form used for user/add and user/edit actions =head1 DESCRIPTION Catalyst Form. =cut has '+item_class' => ( default => 'User' ); has_field 'username' => ( type => 'Text', required => 1, required_message => 'A Username is required', label => 'Username', ); has_field 'name' => ( accessor => 'profile.name', type => 'Text', required => 1, required_massage => 'A Name is required', label => 'Name', ); has_field 'email' => ( accessor => 'profile.email', type => 'Text', required => 1, required_message => 'An email address is required', label => 'Email', ); has_field 'password' => ( type => 'Password', required => 1, required_message => 'A Password is required', label => 'Password', ); has_field 'roles' => ( type => 'Multiple', label => 'Roles', widget => 'CheckboxGroup', ); has_field submit => ( type => 'Submit', value => 'Update', element_cla +ss => ['btn'] ); __PACKAGE__->meta->make_immutable; no HTML::FormHandler::Moose; 1;

I've tried with and without the accessor, and with accessor values "user.profile.name" and "profile.name". According to the documentation ( http://search.cpan.org/~gshank/HTML-FormHandler-Model-DBIC-0.23/lib/HTML/FormHandler/TraitFor/Model/DBIC.pm#DBIC_Relationships ) HTML::FormHandler::TraitFor::Model::DBIC handles many_to_many and belongs_to relationships automatically, but I tried creating the has_one relationship as a belongs_to relationship with no luck.

What am I doing wrong with HTML::FormHandler?

I'm also open to any suggestions regarding database/schema layout or design.

Thanks in advance

Replies are listed 'Best First'.
Re: How to get HTML::FormHandler to update related tables with has_one relationship
by three18ti (Monk) on Feb 24, 2013 at 21:44 UTC

    Ok, I don't think I'm making any progress, but I was able to create Classes for my "Owner" and "ServerType" tables. I used belongs_to relationships, and one works while the other does not... also again, I'm able to view the requisite field in my template, but the form does not recognize the relationship.

    Perhaps I need to figure out a better way to provide a row? I thought that was the whole point of declaring relationships was that created the JOIN, but when I run with DBIC_TRACE=1 all I see is SELECT statements.

    This further adds to my confusion as -some- relationships work while others don't...