[Catalyst] CatalystX::CRUD::Controller::RHTMLO: related database tables and nested forms

Adam Mackler nabble at mackler.org
Wed Jan 13 15:33:27 GMT 2010


Thanks for your quick reply.  Forgive me for re-asking, but since each
decision I make results in an investment of much time, a moment now
confirming my understanding could save me much backtracking later.

Am I correct in paraphrasing you here: when using Rose::DBx::Garden
with Catalyst, the only way to construct a user webpage containing a
form that is "connected" with (i.e., performs CRUD operations on)
multiple, related database tables is with major surgery of the perl
modules as installed from CPAN?  The only way to do it without more
programming than (you accurately assess) I desire to do is to simply
accept that the data for separate tables must be entered on separate
forms on separate webpages?  Is that accurate?

If so, some questions and thoughts:

A question: would this limitation go away if I were still using the
Rose DB and Form objects, but not working from a plant()ed
application? The reason I ask is that I have seen a solution, but it
doesn't work with CatalystX::CRUD::Controller.  I don't want to
dismiss good with bad; in this case Rose Forms may be okay for me but
maybe the CatalystX::CRUD::Controller is a problem?


And a thought: As a newcomer to this general area, it seems suprising
(in one sense at least) that I was able to do multi-table forms with
HTML::FormHandler, which docs make me think is a solution that is
"simpler."  While I haven't (yet?) tried with FormFu, my vague
memories of reading its docs make me think its possible.  My point is
(and again I'm a beginner, no disrespect to Gerda and the FormFu
authors for giving me two more excellent options for working with
forms), but my point is that FormHandler and FormFu seem to be easier
to get started with than RHTMLO, so therefore by the unbending laws of
the universe, since RHTMLO is harder to learn, then it must be in some
way "better" in the end?  Right?

(This is where fans of FormFu and FormHandler are invited to jump in
and make their best cases to lure me from my current path of using
RHTMLO.)

I know that I'm not the first person to want to do multi-table Rose
Forms, since Mr. Siracusa pointed me to this very on-point thread
where he showed how he did it:

http://www.mail-archive.com/rose-db-object@lists.sourceforge.net/msg01443.html

To me, this is a little more than I feel up to, but I did try to
understand it best I could.  Two things come to mind:

First, his solution won't work with CatalystX::CRUD.  He has his
method called "person_from_form" that returns a Rose::DB::Object that
was created from the Rose::HTML::Form, and that DB object contains the
references to the related objects created from the related, nested
forms.  That's just what I want!  The problem is that his
person_from_form() method takes no arguments (besides the caller),
whereas I am using CatalystX::CRUD::Controller::RHTMLO, which calls
person_to_form() and expects to be able to pass to a it Person object
in order to update that object.  So his solution, which doessn't do
such updating, does't work with CatalystX::CRUD::Controller::RHTMLO.

Second, how hard really would it be to create the functionality I
want?  Can I make my "person_to_form()" method (in my case
debtor_to_form) go through all its subforms and add the related
objects?  It doesn't seem to me as if it would be too hard (for
someone competent).  I envision something like this in my Debtor Form:

sub debtor_from_form (
    my ($self) = shift;
    my (@args) = @_;

#   get the main object for the form
    my $debtor = $self->object_from_form(@args);

#   get related object from the related forms
    foreach my $subname ($self->form_names) {
       my $subform = $self->form($subname);
       my $method = $subform->init_object;
       my $sub_object = $subform->$method;
       $debtor->$subname($sub_object);
    }
    return $debtor;
}

I know this won't work as written, but it expresses my general idea:
Can't I just make my debtor_to_form go through all its subforms?....in
fact, couldn't I even subclass the object_from_form() method and make
it recurse so that debtor_from_form can stay the way plant() installed
it, and all <object>_from_form() methods will recurse through their
nested subforms?

But even if that works, there's still the issue of populating the form
fields when making changes to existing database rows.  I wouldn't know
where to start on that one.

In any event, I'll repeat (perhaps unnecessarily) that I'm really not
a programmer, and maybe I've bit off more than I can chew.  Maybe a
simpler (or at least more-used-and-thus-more-documented) solution like
FormFu would be a better choice for my purposes?  Thing is, I just
can't get over how pimped-out this magically-planted app is.  I'd hate
to lose such features if I don't have to.

One thing I haven't mentioned: my database that I'm wanting to build
this app on top of has about forty tables, all related to each other.
I'm concerned that a "simpler" solution such as FormFu might start
breaking down as the complexity of my app grows.

I'm trying to do this with RHTMLO partly because I thought it might be
the best choice for me, but also just because I've found that the only
way to be sure of which solution is the right one is by trying each.
As always, I'm ready to learn why I'm doing things the wrong way, and
what some other possible right ways might be.

Cheers and thanks,
Adam Mackler

P.S. Peter: on behalf of all people who ever wished there were more
documentation, thank you for encouraging others to create such
documentation.  Once I feel competent enough to, I look to make my own
documentary contribution to this realm...but that's a ways off yet.

On Wed, Jan 13, 2010 at 12:53:15AM -0600, Peter Karman wrote:
> Thanks for the detailed report, Adam. I'll try and reply with the detail it 
> deserves.
> 
> Adam Mackler wrote on 1/12/10 8:05 PM:
> 
> >
> >So, now firing up the app that was magically created for me, I have a
> >pulldown menu with the name of app on it.  On this menu I have items
> >for Debtor and Name.  I see an option to create a Debtor, and I get a
> >blank form.  In the HTML source of the form, searching for "name='id'"
> >finds nothing.  So far so good.
> >
> >Now I see that the current_name field has a text field for me to enter
> >the value of the id column of this debtor's row in the names table.
> >What I want to do is to replace this with three text fields for first,
> >middle, and last names.  I think the way to do this is with nested
> >forms.
> 
> You could go down that road, if you wanted to, and certainly RHTMLO 
> supports it (as you discovered). But the RDGC controllers would require 
> some more drastic surgery than what you probably want to attempt.
> 
> Instead, I think you want to use the existing features in RDGC to first 
> create a Name and then relate a Debtor to it. That is a little backwards 
> from how you would think of it as a user, but RDGC is a "bare-metal" db 
> app. That is, it tries to give you a one-to-one reflection of how the db is 
> organized, and if your db is highly normalized (which is a good thing, 
> depending on how you are using it) then the resulting web UI can feel a 
> little "cart before the horse".
> 
> So, in the UI presented to you, if you select Bigk from the menu, then Name 
> -> Create, and create a Name record first, you're on the right track. After 
> you save the Name record, you should see the Related menu on the left, and 
> the option for Debtors. Click Debtors, and then "Create new Debtors" on the 
> right. Enter and save the new Debtor record and you're nearly there. Since 
> you've got a one-to-one going both directions in your schema, you'll want 
> to enter the FK in the 'debtor' column for the original Name record you 
> entered. Then you should be able to click back and forth between the Name 
> and Debtor record you've created, since the FK columns should have a href 
> generated next to each value.
> 
> Rather than viewing FK ints all the time, what I tend to do is create a 
> unique, human-friendly column in each table, or add a method called 
> 'unique_value' in my RDBO subclass that returns a human-friendly value. The 
> 'unique_value' method is called if available.
> 
> Hope that helps. Feel free to ask more questions if it doesn't, and 
> consider adding a write-up of your experience to the Catalyst wiki to help 
> the next folks who stumble along this path. Oh, and doc patches also 
> welcome.
> 
> -- 
> Peter Karman  .  http://peknet.com/  .  peter at peknet.com
> 
> _______________________________________________
> List: Catalyst at lists.scsys.co.uk
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
> Dev site: http://dev.catalyst.perl.org/



More information about the Catalyst mailing list