Rose DB <-> Rose HTML

1 view
Skip to first unread message

James Masters

unread,
May 9, 2008, 5:05:15 AM5/9/08
to Rose::HTML::Objects
So now the nitty gritty. Having validated the form input, I then want
to update my record with any values that have changed. So I naively
did:

my $object = $form->object_from_form(param('updatedbclass')); # the
class of the output object
$object->save;

This fails with "Duplicate entry '643' for key 1". I believe this is
because save only updates for an object that has previously been
loaded or saved where my object was created from a form object, and so
the routine attempts to create a new row instead.

Fair enough - as documented. But what is the best way to do this?
Should I write my own routine that will first load the record and then
go through each field comparing with the object created from the form
updating with any changes and then save. Or does a facility already
exist?

thanks,

James.

John Siracusa

unread,
May 9, 2008, 10:04:54 AM5/9/08
to rose-htm...@googlegroups.com
On Fri, May 9, 2008 at 5:05 AM, James Masters <ja...@mastersgames.com> wrote:
> my $object = $form->object_from_form(param('updatedbclass')); # the
> class of the output object
> $object->save;
>
> This fails with "Duplicate entry '643' for key 1". I believe this is
> because save only updates for an object that has previously been
> loaded or saved where my object was created from a form object, and so
> the routine attempts to create a new row instead.
>
> Fair enough - as documented. But what is the best way to do this?
> Should I write my own routine that will first load the record and then
> go through each field comparing with the object created from the form
> updating with any changes and then save. Or does a facility already
> exist?

If you know for sure you're doing an update, you can always call
$object->update. But IME it's common that a form does not include
every field in a table, so a safer bet is to first load() the object
based on the primary key valye in the form (if any) and then pass that
loaded object to *_from_form(). That way any existing fields are
preserved and any new values from the form are merged with them.

You can usually use the same *_from_form() routine for both add and
update forms with a little effort. (I usually have my "add" form
inherit from my "edit" form or vice versa.)

sub foo_from_form
{
my($self) = shift;

my $foo = My::DB::Foo->new;

if(my $id = $self->field_value('id'))
{
$foo->id($id);
$foo->load;
}

return $self->db_object_from_form($foo);
}

Some of this is mooted by calling $object->save(changes_only => 1)
instead of just plain save(), but I actually usually combine both
approaches, using a *_from_form() method like the above and then also
saving changes only.

Also note than any exceptions thrown in foo_from_form() must be caught
by the caller. It's my usual practice to wrap any form or db-related
tasks in the webapp method inside an eval block, and simply let all
those methods throw exceptions as needed.

-John

James Masters

unread,
May 9, 2008, 11:16:35 AM5/9/08
to Rose::HTML::Objects
That is all really excessively clever. I had missed that one could
start with an existing object. The
$existingobj->load;
$updatedobj = $form->object_from_form($existingobj),
$updatedobject->save(changes_only => 1);

works. The unified object_from_form is also good but the way I've
done things, I will keep separate for now.
Thank you very much.
Reply all
Reply to author
Forward
0 new messages