[Catalyst] Where is the form field lost?

Charlie Garrison garrison at zeta.org.au
Mon Jan 25 08:28:01 GMT 2010


Good evening,

On 25/01/10 at 8:08 AM +0200, orasnita at gmail.com wrote:

>From: "Charlie Garrison" <garrison at zeta.org.au>
>On 24/01/10 at 10:47 PM +0200, Octavian Rasnita <orasnita at gmail.com> wrote:
>
>>I had some problems with InflateColumn::File a few weeks ago which
>>were going to be hard for me to work around. I asked about it on IRC
>>and was told *not* to use the broken InflateColumn::File and use
>>InflateColumn::FS instead.
>
>Can you tell about those problems? I hope I won't create them in the inflator I want to create.

I don't recall exactly, but IC::File had problems with multiple 
'file' columns. I remember, the delete part was completely 
broken if all files were not in the same directory. I was trying 
to patch IC::File so that deleting would work; I was advised to 
use IC::FS rather than trying to fix IC::File. (I don't recall 
who said that, sorry.)

>>Not only did InflateColumn::FS resolve my main issue; it also fixed a
>>couple of frustrating niggles. I found InflateColumn::FS to be more
>>robust all around.
>
>I have also tried InflateColumn::FS but the thing I don't like is that
>it creates random directories and this is good from a security point of
>view, but for ease of use I like the way InflateColumn::File create the
>target dirs.

One of the reasons I found IC::FS so much better, was the extra 
control for things like how files are named/stored on disk. From 
the POD:

fs_file_name
   Provides the file naming algorithm. Override this method to 
change it.
   This method is called with two parameters: The name of the 
column and the column_info object.

_fs_column_dirs
   Returns the sub-directory components for a given file name. 
Override it to provide a deeper directory tree or change the algorithm.

Eg (example from myApp; I used a different naming scheme in the 
end, but this shows the flexibility of IC::FS):

sub fs_file_name {
     my ($self, $column, $column_info) = @_;
     my MIME::Type $img_mimetype = 
MIME::Types->new->type($self->mime_type); #'image/jpeg'
     my $size = $column eq 'media_full_file'  ?
                     'full' :
                $column eq 'media_thumb_file' ?
                     'thumb' :
                $column eq 'media_orig_file'  ?
                     'orig' :
                     '';
     return sprintf("%05d-%s_%s.%s",
         $self->user->id,
         $self->name,
         $size,
         $img_mimetype->subType)
}

I ended up using something very close to the original method, I 
just wanted to add the file extension:

sub fs_file_name {
     my ($self, $column, $column_info) = @_;
     my MIME::Type $img_mimetype = 
MIME::Types->new->type($self->mime_type); #'image/jpeg'
     return sprintf("%s.%s", DBIx::Class::UUIDColumns->get_uuid, $img_mimetype->subType)
}

I'm sure it's possible to use the original file name (from 
upload param), but I didn't want to use that anyway. So again, 
IC:FS was an easy win for me.

Note, I find the sub-dirs created with IC::FS much more 
desirable than putting them all in one directory (for scaling 
reasons). I was looking at ways of patching IC:File to do that 
since I wasn't looking forward to many thousands of directory 
entries in my media dir. And if I find that two-letter sub dirs 
isn't enough (I hope we get that big), I can easily change that 
by overriding _fs_column_dirs.

>With InflateColumn::File the original file name is also used when it is
>stored on the disk, and I just need to put a link to that static file,
>without needing to create a column for storing the MIME type of the
>file and without needing to use code for getting the file and giving it
>to those that request it. If it is possible to do that with
>InflateColumn::FS, please tell me.

Create a method that returns the file path and call that when 
you need to create URL pointing to the file:

sub fs_file_path {
     my ($self, $column) = @_;
     my $fh = $self->$column;
     return $fh->relative( 
$self->result_source->column_info($column)->{fs_column_path} )->stringify;
}

And I created some wrapper methods for each column:

sub media_full_file_path  { 
shift->fs_file_path('media_full_file');  }
sub media_thumb_file_path { 
shift->fs_file_path('media_thumb_file'); }
sub media_orig_file_path  { 
shift->fs_file_path('media_orig_file');  }

In my template:

[%  img_full_src   = 
c.uri_for("/static/media/${user_image.media_full_file_path}" );
     img_thumb_src  = c.uri_for("/static/media/${user_image.media_thumb_file_path}");
-%]

Note, fs_file_path return a two-part path, so the value needs to 
be passed as part of first arg to uri_for. Otherwise, if passed 
as second arg, the slash will get encoded and things may not 
work as expected.


>>If you're going to upload an HTML::FF inflator module tp CPAN, I
>>suggest making it work with InflateColumn::FS instead (or at least in
>>addition to InflateColumn::File).
>
>I have tried that with InflateColumn::File, but without success, but in
>any case, the most important changes were to make it work with
>HTML::FormFu and to be able to do all the operations to the file
>(add/modify/delete), and for beeing able to also do the delete, I need
>to be able to get the file upload field even if it is empty.

Watch out for the delete method in IC::File; it's broken. At 
least it was broken for my usage. And that was pretty much a 
deal breaker for me; that's what got me started on this journey.


Hmm, sounds like I may have just volunteered for Cookbook doc 
patch, or at least an entry on my blog so others can benefit 
from my pain. Does this sound like something that should go in 
the DBIC cookbook?


Charlie

-- 
    Ꮚ Charlie Garrison ♊ <garrison at zeta.org.au>
    〠 PO Box 141, Windsor, NSW 2756, Australia

O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
http://www.ietf.org/rfc/rfc1855.txt



More information about the Catalyst mailing list