FAQ
Greetings:

In brief: I'm using CatalystX::CRUD::Controller::RHTMLO; that class
has a method called form_to_object that wants me to have a method in
my Form called <object>_from_form, where <object> is the object type
and that method name is stored in my controller config as the value of
"init_object". That so-named method is magically created for me in my
Rose::HTML::Form-descended objects by using the amazing plant() method
of Rose::DBx::Garden(::Catalyst).

Question: What do I have to do to my
Rose::DBx::Garden::Catalyst-created application to create a form that
does CRUD operations on data in multiple related tables correctly?
Does the answer to this question have anything to do with the
<object>_from_form method I mentioned above? I am feeling like what I
have to do includes changing that method.

That was the short version.

I'm a relative beginner at using Catalyst, and impairingly I'm more of
a user than a programmer, so I apologize in advance for being behind
the curve. At this point I'm still learning basics. Hopefully this
post may be helpful to anyone trying to do the same thing.

That said, alls I wanna do is have a webpage with an HTML form that
will update related tables in my database simultaneously and
correctly, and populate my multi-table-based form with the correct
data from the related database tables. And my controllers are based
on Rose::DBx::Garden::Catalyst::Controller.

I used plant() from Rose::DBx::Garden::Catalyst to create all the
files of my app. That plant() method calls the plant() in its
superclass, Rose::DBx::Garden, which does most of the work, and then
adds Catalyst-specific files. It's all pretty cool, but finding my
way through everything it made is a bit daunting. I think these files
that plant() made--please correct me--we call scaffolding. Basically
it's my starting point for customizing the application into it's
specified goal.

Right now, my next baby step is to connect two related tables that
share a one-to-one relationship. It's for Big Kelly's Collection
Agency. Big Kelly has a database with two tables: one for debtors,
one for their names. A debtor can have more than one name, but
exactly one name is the current name. I want a form-containing
webpage that Big Kelly can use to update table-column values in both a
debtor's row of the debtors table as well as that same debtor's
current name row in the names table.

My exact procedure leading up to calling the plant() method of
CatalystX::CRUD::Controller::RHTMLO is here in moderate detail:

Firsty, I made my database tables. Here's what part of my postgresql
database for Big Kelly's Collection Agency looks like. (Sorry I don't
know how to get SQL out of postgres.) First the table of debtors:

bigk=# \d debtors;
Table "public.debtors"
Column | Type | Modifiers
-------------------+-----------------------------+--------------------------------------
id | integer | not null default nextval('debtors_id_seq'::regclass)
email | character varying |
current_name | integer |
Indexes:
"debtors_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"debtors_current_name_fkey" FOREIGN KEY (current_name) REFERENCES names(id)
Referenced by:
TABLE "names" CONSTRAINT "names_debtor_fkey" FOREIGN KEY (debtor) REFERENCES debtors(id)

bigk=# \d names
Table "public.names"
Column | Type | Modifiers
-------------+---------------+----------------------------------------------------
id | integer | not null default nextval('names_id_seq'::regclass)
debtor | integer |
last_name | character(21) |
middle_name | character(24) |
first_name | character(24) |
Indexes:
"names_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"names_debtor_fkey" FOREIGN KEY (debtor) REFERENCES debtors(id)
Referenced by:
TABLE "debtors" CONSTRAINT "debtors_current_name_fkey" FOREIGN KEY
(current_name) REFERENCES names(id)

bigk=#



Then I created a Catalyst app:

catalyst.pl BK
cd BK
perl Makefile.PL
From the new app directory I made a file called lib/BKDB.pm to connect
to the database:

package BKDB;
use strict;
use warnings;
use base 'Rose::DB';

BKDB->register_db (
database => 'bigk',
driver => 'Pg',
username => 'sysop'
);
1;

Next I created this script file to do the planting:

#!/usr/bin/perl
use BKDB;
use Rose::DBx::Garden::Catalyst;

my $garden = Rose::DBx::Garden::Catalyst->new(
garden_prefix => 'RDBO',
catalyst_prefix => 'BK',
controler_prefix => 'mycontroller'
db => BKDB->new,
debug => 1,
tt => 1,
include_autoinc_form_fields => 0,
column_to_label =>
sub {
my ($garden_obj, $col_name) = @_;
return join(' ', map { ucfirst($_) } split(m/_/, $col_name));
},
);
$garden->plant('lib');


And I ran that script from the application directory, including the
lib directory on the perl command line. It created a bunch of files.

At that point I edited the new application configuration file, bk.conf
and added the line:

default_view RDGC

Next I copied from my installed perl libraries the file called

CatalystX/CRUD/YUI/TT/crud/tt_config.tt

and put a copy of that file with the same filename into root/crud.
From that file I removed the line that reads:
ThisIsDefTTConfig = 1;

(I have an eventual goal of installing the javascript libraries on my
server, but so far have not been successful.)

I found a plant()-created file called lib/RDBO/Bk/Debtor.pm. This
seems to be how the ORM knows about my debtors database table.

__PACKAGE__->meta->setup(
table => 'debtors',
columns => [
id => { type => 'serial', not_null => 1 },
email => { type => 'varchar' },
current_name => { type => 'integer' },
],
primary_key_columns => [ 'id' ],
foreign_keys => [
name => {
class => 'RDBO::Bk::Name',
key_columns => { current_name => 'id' },
},
],
relationships => [
names => {
class => 'RDBO::Bk::Name',
column_map => { id => 'debtor' },
type => 'one to many',
},
],
);

And in Name.pm I have:

_PACKAGE__->meta->setup(
table => 'names',
columns => [
id => { type => 'serial', not_null => 1 },
debtor => { type => 'integer' },
last_name => { type => 'character', length => 21 },
middle_name => { type => 'character', length => 24 },
first_name => { type => 'character', length => 24 },
],
primary_key_columns => [ 'id' ],
foreign_keys => [
debtor_obj => {
class => 'RDBO::Bk::Debtor',
key_columns => { debtor => 'id' },
},
],
relationships => [
debtors => {
class => 'RDBO::Bk::Debtor',
column_map => { id => 'current_name' },
type => 'one to many',
},
],
);

In the same directory as those files that define my Debtor and Name
Rose::DB::Object-descended objects files are directories called Debtor
and Name, each with a file called Form.pm. These seem to be my
Rose::HTML::Form objects. Each of those Forms has a method called
init_with_debtor or init_with_name and one called debtor_from_form or
name_from_form, respectively. I am under the impression that the
debtor_from_form method is called by form_to_object in
CatalystX::CRUD::Controller::RHTMLO.

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.

http://search.cpan.org/~jsiracusa/Rose-HTML-Objects-0.6061/lib/Rose/HTML/Form.pm#NESTED_FORMS

So I edit the Debtor Form file in lib/RDBO/Bk/Debtor/Form.pm, which is
a descendant of Rose::HTML::Form. Into the build_form method of my
Debtor Form object I add a line:

$self->add_form(name_form => RDBO::Bk::Name::Form->new);

This is a nested form, right? Now I restart the app and go to the
webpage for creating a new debtor. Aha! I have the fields for first,
middle, & last names.

I look at the HTML source and see the last_name text field is an
<input> element containing the name attribute "name_form.last_name".
Okay, that looks like it has enough information for my app to figure
out that the value of that field goes into the names table rather than
the debtors table.

Now I try creating a new debtor record with a name. No dice. I have
to get the app to save the name record related to the debtor record at
the same time.

Still editing my Debtor/Form.pm file, the one with build_form() that I
just amended with add_form(), I make some changes to the
debtor_from_form method. I changed it from this:

sub debtor_from_form {
my $self = shift;
$self->object_from_form(@_);
}

into this:

sub debtor_from_form {
my $self = shift;
my (@args) = @_;
my $debtor = $self->object_from_form(@args);
my $name_form = $self->form('name_form');
my $name_obj = $name_form->name_from_form($name_form->object_class);
$debtor->name($name_obj);
return $debtor;
}

Restart the app, create a debtor with names, and yes, I have added my
data to both the debtors and names tables, and the current_name column
of the newly-created debtor's row in the debtors table correctly
contains the value, newly created, of the id column of the row with
the new debtor's first, middle, & last names. It worked.

But, alas, on the webpage displayed to me after hitting submit, the
first, middle, last name fields have no values. Also, there's another
problem: I didn't metion it above, but it seems that the line adding
the nested name_form into the Debtor::Form:

self->add_form(name_form => RDBO::Bk::Name::Form->new);

within the build_form() method of my Form, that line breaks something.
To wit: when I use the pull-down menu that was magically created for
me, and try to see a list all the debtors in my database, I get no
results, which was working before. That is at the uri:
mycontroller/bk/debtor/search. That Catalyst controller named
Debtor.pm is based on (descended from)
Rose::DBx::Garden::Catalyst::Controller, which is descended from the
CatalystX::CRUD::Controller.

Anyway, the whole time I'm doing this, I'm thinking, I can't be doing
this the right way. It seems like there should be a better way to do
this. I would be eternally grateful to anyone who can understand what
I wrote an shed any light on this for me.

I'm sure there's a way to use CatalystX::CRUD::Controller::RHTMLO to
affect related database tables at the same time. As obvious as it may
seem to be after I know it, I haven't figured it out on my own yet.

Cheers,
Adam Mackler

Search Discussions

  • Peter Karman at Jan 13, 2010 at 6:53 am
    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@peknet.com
  • Adam Mackler at Jan 13, 2010 at 3:32 pm
    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@peknet.com

    _______________________________________________
    List: Catalyst@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/
  • John Siracusa at Jan 13, 2010 at 4:30 pm

    On Wed, Jan 13, 2010 at 10:33 AM, Adam Mackler wrote:
    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.
    Ignoring Catalyst for a moment, here are some general patterns for
    CRUD with RHTMLO (error handling omitted):

    * Show empty creation form:

    # Get form object:

    # Either create a new one:
    $form = MyForm->new;
    # or grab an existing one ans reset it:
    #$form = GetMyForm();
    #$form->reset();

    # Initialize form with query parameters (if any)
    $form->params(GetQueryParamsSomehow());
    $form->init_fields();

    # Show the page with the form on it
    ShowCreationPageWithForm($form);

    * Handle a "create" form submission:

    # Get form object (same as before)
    $form = ...

    # Initialize form with query parameters (same as before)
    ...

    # Get object form form
    $object = $form->my_whatever_from_form();

    # Save object;
    $object->save;

    # Redirect to success page
    ...

    * Show an edit form:

    # Get object to be edited
    $id = IdFromQueryParameters();
    $object = MyObject->new(id => $id)->load;

    # Get form object (same as before)
    $form = ...

    # Initialize form with object
    $form->init_with_my_whatever($object);

    # Show the edit page with the form on it
    ShowEditPageWithForm($form);

    * Handle a "update" form submission:

    # Get object to be updated (same as before)
    $object = ...

    # Get form object (same as before)
    $form = ...

    # Initialize form with query parameters (same as before)
    ...

    # Get the updated object from form:
    # (Note that the existing object is passed as an arg.)
    $object = $form->my_whatever_from_form($object);

    # Save the updated object
    $object->save;

    # Redirect to success page
    ...

    In all cases, the $object could be a tree of related objects. In
    those cases, the load() calls to get an existing $object should use
    the load(with => ...) form (or perhaps a Manager call) to get a fully
    populated tree of objects.

    As you can see, there's a lot of common stuff that can be factored
    out. For example, in my web apps, I usually have a set of pre-created
    form objects stashed away by name (e.g., create_form, edit_form, etc.)
    and a prepare_form() method that does all the form reset()ing and
    initialization with params:

    # Get form, reset(), and initialized with the current query params
    $form = $mywebapp->prepare_form('create_form');
    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;
    }
    That's the basic idea: delegate sub-object handling to the sub-forms
    that know how to handle them. The init_with_db_object() and
    db_object_from_form() methods linked to earlier[1] automate this
    process as long as you match up the sub-form names with the
    relationship/fk names in your RDBO classes.
    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.
    Pass a fully populated object tree to init_with_db_object() and it'll
    do this for you by matching up relationship/fk names with sub-form
    names. Step through the code to see how it works, and how you could
    manually do the same thing.

    -John

    1. http://www.mail-archive.com/rose-db-object@lists.sourceforge.net/msg01443.html
    and bug fix:
    http://www.mail-archive.com/rose-db-object@lists.sourceforge.net/msg01464.html
  • Peter Karman at Jan 13, 2010 at 10:38 pm

    John Siracusa wrote on 01/13/2010 10:30 AM:
    On Wed, Jan 13, 2010 at 10:33 AM, Adam Mackler wrote:
    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.
    Ignoring Catalyst for a moment, here are some general patterns for
    CRUD with RHTMLO (error handling omitted):
    <snip>

    fwiw, the CXC RHTMLO code implements all those general patterns.
    In all cases, the $object could be a tree of related objects. In
    those cases, the load() calls to get an existing $object should use
    the load(with => ...) form (or perhaps a Manager call) to get a fully
    populated tree of objects.
    yes, I use load(with => ...) in my own CXC-based apps.

    <snip>
    Pass a fully populated object tree to init_with_db_object() and it'll
    do this for you by matching up relationship/fk names with sub-form
    names. Step through the code to see how it works, and how you could
    manually do the same thing.
    yes. I think CXC can handle all these things. Again it is just thin
    glue. I think the OP's obstacles are that CXC::YUI's View doesn't
    present subforms at all.

    --
    Peter Karman . http://peknet.com/ . peter@peknet.com
  • Peter Karman at Jan 13, 2010 at 10:33 pm

    Adam Mackler wrote on 01/13/2010 09:33 AM:
    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?
    That's pretty accurate. However, let me clarify some terms to make sure
    we're talking about the same thing:

    * Rose::DBx::Garden creates scaffolding only. It creates RDBO-based and
    RHTMLO-based classes, which assume 1 table == 1 form. There is no
    generation of code to handle subforms, though as you experiences, it's
    relatively easy to add those later. RDG just tries to remove the tedium
    of creating all the RHTMLO classes just like RDBO::Loader does for RDBO
    classes.

    * Rose::DBx::Garden::Catalyst extends RDG to create Catalyst Controller
    and Model scaffolding. The assumption is 1 table == 1 form == 1
    controller class == 1 model class. The base Controller, Model and View
    classes in RDGC are simple subclasses of CatalystX::CRUD::YUI.

    * CatalystX::CRUD::YUI is a whole Catalyst application. CXCY has all the
    .js and .tt files included so you get the UI for free, which you can
    extend and customize by overriding .tt files in your local app's
    root/crud directory. The limitations you are encountering are with the
    View (the .tt and .js), not anything with CatalystX::CRUD or the CXCY
    .pm files in particular I don't think. The assumption of 1 table == 1
    form == 1 controller == 1 model is baked into the View in
    CatalystX::CRUD::YUI. You don't have to use that View; you can write others.

    * CatalystX::CRUD is the underlying framework. Again, it assumes 1
    controller == 1 table == 1 form. CXC is intentionally agnostic with
    regard to View. CatalystX::CRUD::YUI is just one implementation that
    works out of the box with the simplest of assumptions about 1
    controller, 1 table, etc.
    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?
    The CatalystX::CRUD::Controller is not the problem, I don't think. I
    think the problem is presentation (View). See above.

    <snip>
    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.
    You might look at Catalyst::Plugin::AutoCRUD. It's designed for people
    who don't want to extend or modify their code very much, and is very
    nice imo.
    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.
    RHTMLO is really nice for programmers who think like John. I happen to
    be one. If you don't want to program, then something that Just Works is
    probably a better choice.
    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.
    heh. I'm just lazy when it comes to documentation. Perhaps it is
    backlash from my time as a technical writer. :)


    --
    Peter Karman . http://peknet.com/ . peter@peknet.com

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedJan 13, '10 at 2:03a
activeJan 13, '10 at 10:38p
posts6
users3
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2022 Grokbase