[Catalyst] Where is the form field lost?

Octavian Rasnita orasnita at gmail.com
Sun Jan 24 20:47:06 GMT 2010


From: "Bill Moseley" <moseley at hank.org>
> On Sun, Jan 24, 2010 at 8:31 AM, Octavian Rasnita 
> <orasnita at gmail.com>wrote:
>>
>>
>>> Give your upload field(s) a name like "upload_1"  and then see if it
>>> exists
>>> in uploads.
>>>
>>
>> I gave it the name "file", but if the file is not uploaded, it doesn't
>> appear in uploads(). (I hope "file" is OK as a name, no?)
>
>
> Why do you need to know that a field existed on the form but was submitted
> empty?  Checkboxes don't submit if not checked.  You get what's included 
> in
> the post and have to work from that.  Either you have an upload or not,
> right?

I made a InflateColumn::FileUpload inflator similar to InflateColumn::File, 
which also works with HTML::FormFu and it has an additional feature.

The files can be uploaded by just using:

sub add : Local FormConfig {
  my ($self, $c) = @_;

  my $form = $c->stash->{form};

  if ($form->submitted_and_valid) {
    $form->model->create;
    #Print the success message and redirect here
  }
}

And the existing record that contains file uploads can be also modified by 
using:

sub edit : Local FormConfig {
  my ($self, $c, $id) = @_;

  my $form = $c->stash->{form};
  my $record = $c->model("DB::TableName")->find($id);

  if ($form->submitted_and_valid) {
    $form->model->update($record);
    # Here print the success message and redirect
  }
  else {
    $form->model->default_values($record);
  }
}

In the Result::TableName there should be:

# If the user might need to replace the existing uploaded file with another 
one:
__PACKAGE__->mk_group_accessors(simple => 'file_replace_validator');

__PACKAGE__->load_components("InflateColumn::FileUpload");

__PACKAGE__->add_columns(
"file", {
data_type => "VARCHAR",
default_value => undef,
is_nullable => 1,
size => 255,
is_file_upload => 1,
file_upload_path => $ENV{the_directory_where_the_files_will_be_stored},
});

The form used to add new records will contain a common HTML::FormFu File 
element (and other elements needed).

The form used for editing can contain a checkbox with the name 
"file_replace_validator", or if the name of the file upload field would be 
"foo", that checkbox will be named "foo_replace_validator". I created an 
accessor for it because there should be no column with this name in the db 
table (although I may find a solution to not need it at all).

When the user will use the form for creating a new record, it will upload 
the file if a file is loaded in the form, or it will send the form without 
that field so here there is no problem.

When the user will use the editing form, he or she will have the option of 
choosing if she wants to replace the existing file.
If she doesn't check that checkbox, it doesn't matter if she uploads a file 
in that field, because the original file won't be changed.
If she checks it, it means that she wants to replace the existing file with 
the new file uploaded. If she checks it but she doesn't upload any file, it 
means that she wants to replace the existing file with nothing, so she just 
wants to delete the existing file.

So with this inflator one can upload a new file, delete an existing file, 
and replace an existing file with another one by using just 2 forms which 
are the same, but the editing form may have that aditional checkbox for 
confirming the replacement.

If the user will delete the record, the file attached will be also deleted 
from the disk.
If the user will access the record, it will get a hashref with 2 elements - 
the filename, and the IO::File handle to that file so she will be able to 
use the same syntax as the InflateColumns::File does it:

<a href="[% c.uri_for('/static/path_to_dir', row.id, row.file.filename).path 
%]">[% row.file.filename | html %]</a>

The problem is that if DBIC doesn't find any file upload field, the inflator 
is not used at all, so it doesn't do anything, although it should see that 
there is an empty  file upload field that has the is_upload_file attribute, 
see that the user has chosen to replace the existing file with it,
so it should delete the existing file.

For making it work, I need to add the following ugly code in the edit 
action:

if ($form->submitted_and_valid) {
  #Set a hashref for the empty file field because otherwise FileUpload 
inflator ignores it
  unless ($form->param('file')) {
    $c->req->params->{file} = {};
    $form->process;
  }
  $form->model->update($anunt);
  #...
}

I didn't want to load this inflator to CPAN until I solve this issue, but if 
you or somebody else wants, I can send you the source code.

> Without commends in the code or documentation can't really know the 
> author's
> reasoning.   I guess it assume uploads go to temp files and no need to do
> that if there's no content.

If the file is an empty one, I guess there shouldn't be a big issue if the 
file would go to the temp directory. I think it could get deleted as the 
other non-empty files which are uploaded there.
Octavian




More information about the Catalyst mailing list