Does Rails need more useful form helpers?

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.

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.

Stephen F. 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
  1. 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.

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

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?

Stephen F. 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.