FAQ
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.

Thank you.

Octavian

Search Discussions

  • Carl Franks at Dec 18, 2009 at 10:37 am

    2009/12/17 Octavian R??ni?? <orasnita@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
  • Octavian Rasnita at Dec 18, 2009 at 10:26 pm
    From: "Carl Franks" <fireartist@gmail.com>
    2009/12/17 Octavian R??ni?? <orasnita@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
  • Octavian Rasnita at Dec 19, 2009 at 3:24 pm
    From: "Carl Franks" <fireartist@gmail.com>

    2009/12/17 Octavian R??ni?? <orasnita@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 made an HTML::FormFu transformer that just needs to set a {} instead an
    undef value for a File element, but it doesn't work. If I use the same
    transformer for a Text field, it works fine.

    Is the File element special and it can't be transformed?

    As a test, I put the transformer to return a static value of "blabla". It is
    returned fine for a Text element, but for the File type element, after
    applying the transformer, the value is a null one.

    I have printed:
    $form->param('file')
    and
    $c->req->params->{file}

    after applying the transformer, but both of them contain just a null value.

    Thanks.

    Octavian

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouphtml-formfu @
categoriesperl, catalyst
postedDec 17, '09 at 7:43p
activeDec 19, '09 at 3:24p
posts4
users2
websitemetacpan.org...

2 users in discussion

Octavian Rasnita: 3 posts Carl Franks: 1 post

People

Translate

site design / logo © 2022 Grokbase