html-formhandler-model-dbic
html-formhandler-model-dbic copied to clipboard
Unique constraints do not work properly across a belongs_to relationship
If you have a DB model, something like:
__PACKAGE__->add_columns(
"id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0, sequence => "roles_id_seq" },
"body_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
"name", { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("roles_body_id_name_key", ["body_id", "name"]);
__PACKAGE__->belongs_to(
"body", "App::DB::Result::Body", { id => "body_id" },
{ is_deferrable => 0, on_delete => "CASCADE,", on_update => "NO ACTION" },
);
And a matching form (which needs body
to work, body_id
does not):
has_field 'name' => ( required => 1 );
has_field 'body' => ( type => 'Select', empty_select => 'Select a body', required => 1 );
And your database has three rows:
- Body A, name "123"
- Body A, name "456"
- Body B, name "789"
Then the following happens:
- Editing row 1 to Body A, name "456" – works fine, you get the "Duplicate value for [_1] unique constraint" error message.
- Editing row 1 to Body B, name "789" – validation incorrectly passes, it tries to update and dies with a database error.
- Creating a new entry, Body A, name "123" – validation incorrectly passes, it tries to insert and dies with a database error.
This is because the form column is body
but the database field is body_id
. Here is the bit of code responsible:
https://github.com/gshank/html-formhandler-model-dbic/blob/e580d8aa7803ff0f14df8f588a663cde0b8bd5fb/lib/HTML/FormHandler/TraitFor/Model/DBIC.pm#L492-L495
$value
will have a body
entry, not a body_id
entry, from the submitted form. So it always falls back to the item lookup, so on creation that's nothing and on editing the body is the original body not the new one. In both those cases it therefore doesn't find the $value->{body}
entry and incorrectly passes validation.
It needs to know how to turn either body_id into body or vice-versa, at the accessor for those columns, not the actual column names, but I'm not sure how best to do that.