Forum: Ruby on Rails Does Rails need more useful form helpers?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
9004a070a9222f1d3047f15ef6853219?d=identicon&s=25 Stephen Friedman (Guest)
on 2006-04-24 17:02
I have been using rails professionally for only a month and a half now,
but I am continually running into problems with form helpers and
accessing multiple objects on a single page. To whit:

1. While text_field and text_area and such all support the :index
option, the select helper does not.

2. When appending the text '[]' to a helper's object name, the id is
inserted into the brackets --- but only for existing objects. While it
is understandably difficult as new objects have no ids, a method must
exist somewhere to provide these form helpers with a unique way to
communicate their unique data to their responding controllers. One
suggestion is to create the option to specify the object attribute that
will be used to fill the '[]'s. The example for which I'm having to work
around this is an administrative form to generate promotional contact
forms. These forms each have up to 6 questions and each question can
have up to 4 answers. Thus in the model, Promo has_many PromoQuestion
which has_many PromoAnswer. So I am dealing with having to iterate over
three levels of hierarchical data both in the edit form and in the
creation form. It does not seem Rails is designed to handle this type of
form terribly simply. While I understand that this type of form is
possible, its implementation seems far from elegant.

3. Rails hierarchical model objects seem to support the creation of a
tree of new objects that can then be saved with @parent.save. But
modifying this same tree afterwards does not. Should there not be a way
to modify attributes of existing child objects and mark them as "to be
saved" so that when @parent.save is called to update the parent, all the
child objects are also updated? This does not seem to be the case, as I
experienced with the self-same promo example above. Calling @parent.save
after modifying @parent.child.attributes = {...} does not save the
modifications to the child.

Perhaps there are undocumented features of which I am not aware. If this
is the case, then my issue becomes one with the documentation.

And perhaps I just do not understand the elegant way to perform such
tasks as those above. If so, I am eager to learn, and would greatly
appreciate being pointed to the appropriate documentation.
9004a070a9222f1d3047f15ef6853219?d=identicon&s=25 Stephen Friedman (Guest)
on 2006-04-24 17:44
I forgot to complete my sugestion in #2 above. If one could set the
attribute used with the []s in form helpers, I could, in my example
above, use question_number and answer_number to distinguish data for the
various child objects regardless of whether they were new objects to be
created or existng objects to be updated.

This brings up another issue that I feel should have a simple solution.
The solution above only works if the question_number AND answer_number
are used to identify the answer objects. Currently the [] notation for
form helpers does not allow the definition of multiple indices.

But this above solution may not even be an acceptable final solution.
New objects may not have something as simple as a question_number with
which to reference themselves. And yet it seems something is needed to
allow the creation of multiple dependent items in a single form. Perhaps
some means of creating temporary ids for each new object, saving them to
the flash and using those ids to distinguish []-marked attributes for
new objects.

Another suggestion would be a way to tell a form helper about a
hierarchy of objects (or have it intuitively deduce them?). Ideally, it
would seem that while the Promo object's attributes exist in params as
promo[title], promo[description] and so forth that its children's data
should exist in params as promo[promo_questions][id][question_text] and
promo[promo_questions][id][promo_answers][id][answer_text] (where "id"
would be replaced by the actual id of the existing object or an empty
string for new objects). This should then be able to be passed to
@promo.update_attributes() and @promo.new() alike to create or update
all these items in one clean, elegant swoop.

And finally, as I said in my previous post, perhaps this elegance exists
and I simply do not know about it. Or perhaps this elegance does not
exist for some intended purpose or reason.
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2006-04-25 01:38
(Received via mailing list)
Stephen Friedman wrote:

> 1. While text_field and text_area and such all support the :index
> option, the select helper does not.

The select and collection_select helpers support the index option
in their html_options hash, so you have to do something like:

    select :object, :method, {}, :index => 3


> 2. When appending the text '[]' to a helper's object name, the id is
> inserted into the brackets --- but only for existing objects. While it
> is understandably difficult as new objects have no ids, a method must
> exist somewhere to provide these form helpers with a unique way to
> communicate their unique data to their responding controllers. One

I will discuss this in a reply to your follow-up email.


> 3. Rails hierarchical model objects seem to support the creation of a
> tree of new objects that can then be saved with @parent.save. But
> modifying this same tree afterwards does not. Should there not be a way
> to modify attributes of existing child objects and mark them as "to be
> saved" so that when @parent.save is called to update the parent, all the
> child objects are also updated? This does not seem to be the case, as I
> experienced with the self-same promo example above. Calling @parent.save
> after modifying @parent.child.attributes = {...} does not save the
> modifications to the child.

I agree that a common method for both creating and updating a tree of AR
objects would greatly simplify controller code. I have a plugin
half-written
that does just that, keeping track of what attributes and associations
have been changed, so that a save of the parent object does all the
work.

--
We develop, watch us RoR, in numbers too big to ignore.
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2006-04-25 02:11
(Received via mailing list)
Stephen Friedman wrote:
> I forgot to complete my sugestion in #2 above. If one could set the
> attribute used with the []s in form helpers, I could, in my example
> above, use question_number and answer_number to distinguish data for the
> various child objects regardless of whether they were new objects to be
> created or existng objects to be updated.

Yes, you can use the :index option to uniquely number or name both new
and existing objects.

> This brings up another issue that I feel should have a simple solution.
> The solution above only works if the question_number AND answer_number
> are used to identify the answer objects. Currently the [] notation for
> form helpers does not allow the definition of multiple indices.

In order to use multiple indices you have to either use the _tag
versions of the form helpers, or set the name explicitly:

<% @promo.questions.each_with_index |@q, qnum| do
    prefix = "promo[promo_questions][#{qnum}]" %>
<%= text_field :q, :question_text, :name => prefix + '[question_text]'
%>
<% @q.answers.each_with_index |@a, anum| do %>
<%= text_field :a, :answer_text, :name => prefix +
"[answer_text][#{anum}]" %>
<% end
    end %>

> But this above solution may not even be an acceptable final solution.
> New objects may not have something as simple as a question_number with
> which to reference themselves. And yet it seems something is needed to
> allow the creation of multiple dependent items in a single form. Perhaps
> some means of creating temporary ids for each new object, saving them to
> the flash and using those ids to distinguish []-marked attributes for
> new objects.

A common synthetic reference id like a question number is probably
better than using the id attribute for existing objects combined with a
unique temporary id for new object.  Existing object ids can either
be determined from their synthetic ids, or placed in the form as
hidden fields.

> Another suggestion would be a way to tell a form helper about a
> hierarchy of objects (or have it intuitively deduce them?). Ideally, it
> would seem that while the Promo object's attributes exist in params as
> promo[title], promo[description] and so forth that its children's data
> should exist in params as promo[promo_questions][id][question_text] and
> promo[promo_questions][id][promo_answers][id][answer_text] (where "id"
> would be replaced by the actual id of the existing object or an empty
> string for new objects). This should then be able to be passed to
> @promo.update_attributes() and @promo.new() alike to create or update
> all these items in one clean, elegant swoop.

An update_attributes method that worked hierarchically like this would
be nice.

--
We develop, watch us RoR, in numbers too big to ignore.
9004a070a9222f1d3047f15ef6853219?d=identicon&s=25 Stephen Friedman (Guest)
on 2006-04-25 18:09
My apologies about the :index option for select's. I thought I tried
that but I guess I didn't.

> In order to use multiple indices you have to either use the _tag
> versions of the form helpers, or set the name explicitly:
>
> <% @promo.questions.each_with_index |@q, qnum| do
>     prefix = "promo[promo_questions][#{qnum}]" %>
> <%= text_field :q, :question_text, :name => prefix + '[question_text]'
> %>
> <% @q.answers.each_with_index |@a, anum| do %>
> <%= text_field :a, :answer_text, :name => prefix +
> "[answer_text][#{anum}]" %>
> <% end
>     end %>

You agree, I assume, that this is an ugly approach not worthy of the
elegance of rails. In my opinion, it would make for much cleaner rails
applications if rails understood multiple indices (e.g.: :index =>
[question_number, answer_number]) or naturally handled hierarchical
data. Or both.

> A common synthetic reference id like a question number is probably
> better than using the id attribute for existing objects combined with a
> unique temporary id for new object.  Existing object ids can either
> be determined from their synthetic ids, or placed in the form as
> hidden fields.

It was an off-the-cuff thought. I agree, two sets of ids is not a good
idea. I was worried that if synthetic reference ids became the primary
method of handling these situations, applications would eventually crop
up where such an id could not be synthesized. However, I'm not sure what
that situation would be. Collections of new objects being generated all
at once need to be referenced somehow, I presume.

> An update_attributes method that worked hierarchically like this would
> be nice.

I agree. I think this is the best solution so far. Personally, I'd like
to see it work with both update_attributes() and new(). Perhaps rails
can use array index 0 to signify new items to be added, since this will
never be a database record id. All new object data can be placed into an
array underneath this index while existing objects to be modified would
remain under array indices matching their ids. I think this solution
both covers a generic scope of applications and has the elegance I've
come to expect from rails. Are there any problems with this solution I
haven't thought of?
This topic is locked and can not be replied to.