[html-formfu] Accessing a form element which is not in the table
Octavian Râşniţă
orasnita at gmail.com
Fri Dec 18 22:26:56 GMT 2009
From: "Carl Franks" <fireartist at gmail.com>
2009/12/17 Octavian Râşniţă <orasnita at gmail.com>:
> Hi,
>
> Is it possible to access (in a DBIx::Class inflator) an HTML::FormFu
> element
> that doesn't have a corresponding field in the db table?
>
> I need to let the user specify an option in a separate form field
> (checkbox), and depending on that option to replace or not replace another
> field in the database, but the value of that checkbox should not be
> entered
> in the database because there is no field for it there.
I suspect this logic should be handled by the form - not the database layer.
I'd suggest writing a HTML::FormFu::Transformer subclass to do it.
Carl
I found how to do that, by creating an accessor:
__PACKAGE__->mk_group_accessors(simple => 'file_replace_validator');
where "file_replace_validator" is a column that can be accessed in $row, but
is not inserted/updated to DB.
So I made a module temporarily named DBIx::Class::InflateColumn::FileUpload
that can be used with HTML::FormFu::Model::DBIC (with 2 issues).
This module allow file uploads when creating new records, file deletions and
replacements.
It needs just a column "ID" and a column that holds the file name.
The HTML::FormFu could have one more field named file_replace_validator,
which could be a checkbox.
If the form doesn't have that checkbox, the file is uploaded and inserted in
the DB.
If the form has that checkbox and it is not marked, the file previously
uploaded is not replaced, no matter if a new file is uploaded or not.
If the form has the checkbox and it is marked for confirming the
replacement, the file from the server is replaced with the new file
uploaded.
If the form has the checkbox and it is marked for confirming the
replacement, but no new file is uploaded, the file previously uploaded is
deleted (and the directory it is stored in also, if it doesn't contain other
files - from the same recordset).
In order to use this module, the following settings must be done:
In the DBIC Result for the table that holds the files:
__PACKAGE__->mk_group_accessors(simple => 'file_replace_validator');
__PACKAGE__->load_components("InflateColumn::FileUpload");
__PACKAGE__->add_columns(
"id", {
data_type => "INT",
default_value => undef,
is_nullable => 0,
size => 10,
is_auto_increment => 1,
},
"file", {
data_type => "VARCHAR",
default_value => undef,
is_nullable => 1,
size => 255,
is_file_upload => 1,
file_upload_path => '/the/path/to/the/dir',
#or
file_upload_path => MyApp->path_to('the', 'path', 'to', 'dir'),
});
And in the Catalyst controller it should be just:
my $record = $c->model("DB::Records")->find($id);
my $form = $c->stash->{form};
if ($form->submitted_and_valid) {
$form->model->update($record);
$c->res->redirect($c->uri_for("/"));
}
else {
$form->model->default_values($record);
}
But unfortunately if the File element is submitted empty, the "file" field
gets the value undef, and if the value of a column is undef,
DBIx::Class::InflateColumn will ignore it in the deflator because it accepts
only non-scalar references there.
So the file is simply set to null in the DB and not deleted from the hard
disk of the server.
Because of this, I needed to manually set the "file" field to {} but the
code becomes much uglier.
And another issue is that the file handle $record->file->{handle} doesn't
get out of scope after the line:
$form->model->default_values($record);
although it should do it, so I needed to add another line that undef it.
With these 2 fixes, the module works fine, and it is very helpful, but
unfortunately these 2 fixes look ugly, like in:
my $record = $c->model("DB::Records")->find($id);
my $form = $c->stash->{form};
if ($form->submitted_and_valid) {
unless ($form->param('file')) {
$c->req->params->{file} = {};
$form->process;
}
$form->model->update($record);
$c->res->redirect($c->uri_for("/"));
}
else {
$form->model->default_values($record);
undef $record->file->{handle} if $record->file;
}
Even with these few lines of code added it could be very helpful, because it
shouldn't be named explicitly all the row fields as when we create the row
with ->create().
I have tried to use DBIx::Class::InflateColumn::FS and
DBIx::Class::InflateColumnFile for doing file uploads, and even tried to
modify DBIx::Class::InflateColumn::File, but none of them could do what I
want (replacing/deleting the file previously uploaded based on a checkbox's
state.
So I made DBIx::Class::InflateColumn::FileUpload which was inspired by
DBIx::Class::InflateColumn::File.
Please help me to avoid needing to use those 2 fixes, or at least please
tell me if what I want is impossible and due to some restrictions other
modules can't be modified to make it work better, to know if I should
continue or not working for it.
Thank you very much.
Octavian
More information about the HTML-FormFu
mailing list