Forum: Ruby on Rails Adding form fields (extending a form) on the fly

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.
1a161d16b292cbacee7b4563bd0c72e8?d=identicon&s=25 goldshuv (Guest)
on 2006-01-23 09:49
Hello,

I just can't seem to find a way to extend a form dynamically in ROR.

Say I am writing a recipe website. There is one form to enter the
recipe. There is room for N number of ingredients (let's say a text
field for each ingredient name and selection list for the amount). What
if the user wants to add more than N ingredients as he types them in?
how do I do this without a POST, and have those new fields included in
the request (i guess they need to have a unique name and id).

thank you.
Alon.
337cdd270761e0e6f4356de45b04d388?d=identicon&s=25 Jonathan Viney (jonny)
on 2006-01-23 13:48
You could have a link on the page called 'Add extra ingredient field'
that uses ajax to add in more fields as necessary. Put the ingredient
field in a partial (_ingredient.rhtml) so you don't have to repeat
yourself.

View:

<div id="ingredients">
  <% 5.times do %>
    <%= render :partial => 'ingredient' %>
  <% end %>
</div>
<%= link_to_remote 'Add extra ingredient', :update => 'ingredients',
:position => :bottom, :url => { :action => :extra_ingredient } %>

Controller:

def extra_ingredient
  render :partial => 'ingredient'
end

I haven't tested this, but something like this should work fine.

Cheers, Jonny.

goldshuv wrote:
> Hello,
>
> I just can't seem to find a way to extend a form dynamically in ROR.
>
> Say I am writing a recipe website. There is one form to enter the
> recipe. There is room for N number of ingredients (let's say a text
> field for each ingredient name and selection list for the amount). What
> if the user wants to add more than N ingredients as he types them in?
> how do I do this without a POST, and have those new fields included in
> the request (i guess they need to have a unique name and id).
>
> thank you.
> Alon.
1a161d16b292cbacee7b4563bd0c72e8?d=identicon&s=25 goldshuv (Guest)
on 2006-01-23 14:49
Jonny,

Thanks a lot. I appreciate it. I did try something like this earlier but
I am running into a problem. The form may have all the extra fields the
user requested, but they all have the same name and id:

for example, if my text_field looks something like this

<%= text_field(:ingredient, :name) %>

rendering it more times will render the same exact thing over and over

<%= text_field(:ingredient, :name) %>
<%= text_field(:ingredient, :name) %>
<%= text_field(:ingredient, :name) %>
...
...

and when the form is submitted the request will include only *one* entry
for ingredient => { name => "sometext"}. and all the text that the user
entered (besides the first one) will not be there.

thanks,
Alon.



Jonathan Viney wrote:
> You could have a link on the page called 'Add extra ingredient field'
> that uses ajax to add in more fields as necessary. Put the ingredient
> field in a partial (_ingredient.rhtml) so you don't have to repeat
> yourself.
>
> View:
>
> <div id="ingredients">
>   <% 5.times do %>
>     <%= render :partial => 'ingredient' %>
>   <% end %>
> </div>
> <%= link_to_remote 'Add extra ingredient', :update => 'ingredients',
> :position => :bottom, :url => { :action => :extra_ingredient } %>
>
> Controller:
>
> def extra_ingredient
>   render :partial => 'ingredient'
> end
>
> I haven't tested this, but something like this should work fine.
>
> Cheers, Jonny.
>
> goldshuv wrote:
>> Hello,
>>
>> I just can't seem to find a way to extend a form dynamically in ROR.
>>
>> Say I am writing a recipe website. There is one form to enter the
>> recipe. There is room for N number of ingredients (let's say a text
>> field for each ingredient name and selection list for the amount). What
>> if the user wants to add more than N ingredients as he types them in?
>> how do I do this without a POST, and have those new fields included in
>> the request (i guess they need to have a unique name and id).
>>
>> thank you.
>> Alon.
4ecb543bcbe929f29ca6baf0ef56e514?d=identicon&s=25 Michael Bannister (michaelb)
on 2006-01-23 15:31
I'm about to do something similar.  Have a look on here:
http://wiki.rubyonrails.org/rails/pages/Understand...

You need to do something like
<% index = Time.now.to_s -%>
<%= text_field("ingredient[#{index}]", :name) %>

to generate a temporary key for each ingredient.  But in the action that
actually creates/saves all the ingredients, don't use this key as the
id, instead let the database autonumber them for you (not 100% sure on
details of this bit as I haven't done it yet!)

Michael

goldshuv wrote:
> Jonny,
>
> Thanks a lot. I appreciate it. I did try something like this earlier but
> I am running into a problem. The form may have all the extra fields the
> user requested, but they all have the same name and id:
>
> for example, if my text_field looks something like this
>
> <%= text_field(:ingredient, :name) %>
>
> rendering it more times will render the same exact thing over and over
>
> <%= text_field(:ingredient, :name) %>
> <%= text_field(:ingredient, :name) %>
> <%= text_field(:ingredient, :name) %>
> ...
> ...
>
> and when the form is submitted the request will include only *one* entry
> for ingredient => { name => "sometext"}. and all the text that the user
> entered (besides the first one) will not be there.
>
> thanks,
> Alon.
>
>
>
> Jonathan Viney wrote:
>> You could have a link on the page called 'Add extra ingredient field'
>> that uses ajax to add in more fields as necessary. Put the ingredient
>> field in a partial (_ingredient.rhtml) so you don't have to repeat
>> yourself.
>>
>> View:
>>
>> <div id="ingredients">
>>   <% 5.times do %>
>>     <%= render :partial => 'ingredient' %>
>>   <% end %>
>> </div>
>> <%= link_to_remote 'Add extra ingredient', :update => 'ingredients',
>> :position => :bottom, :url => { :action => :extra_ingredient } %>
>>
>> Controller:
>>
>> def extra_ingredient
>>   render :partial => 'ingredient'
>> end
>>
>> I haven't tested this, but something like this should work fine.
>>
>> Cheers, Jonny.
>>
>> goldshuv wrote:
>>> Hello,
>>>
>>> I just can't seem to find a way to extend a form dynamically in ROR.
>>>
>>> Say I am writing a recipe website. There is one form to enter the
>>> recipe. There is room for N number of ingredients (let's say a text
>>> field for each ingredient name and selection list for the amount). What
>>> if the user wants to add more than N ingredients as he types them in?
>>> how do I do this without a POST, and have those new fields included in
>>> the request (i guess they need to have a unique name and id).
>>>
>>> thank you.
>>> Alon.
5b279d677924919326946ef11330d3e4?d=identicon&s=25 Brandt Lofton (Guest)
on 2006-01-23 16:31
(Received via mailing list)
I do believe you can also specify the recipes to be an array.  Try

<%= text_field("ingredient", :name[] %>

Or something to that effect.  I'm 99% sure there is a way to do this,
but I
don't have time to investigate or test atm.

-B
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-01-23 17:35
(Received via mailing list)
On Mon, Jan 23, 2006 at 01:48:45PM +0100, Jonathan Viney wrote:
} You could have a link on the page called 'Add extra ingredient field'
} that uses ajax to add in more fields as necessary. Put the ingredient
} field in a partial (_ingredient.rhtml) so you don't have to repeat
} yourself.
[...]

There is no need for AJAX. Take a look at
http://www.anthropohedron.net/bookmarkfeeds/ for an example that just
uses
JavaScript to create a new line and I handle it with Ruby pretty easily.
The source is freely available (it was a simple toy I used to learn Ruby
and RoR, so consider it public domain) at
http://www.anthropohedron.net/bookmarkfeeds/src.tgz

} I haven't tested this, but something like this should work fine.
} Cheers, Jonny.
--Greg

} goldshuv wrote:
} > Hello,
} >
} > I just can't seem to find a way to extend a form dynamically in ROR.
} >
} > Say I am writing a recipe website. There is one form to enter the
} > recipe. There is room for N number of ingredients (let's say a text
} > field for each ingredient name and selection list for the amount).
What
} > if the user wants to add more than N ingredients as he types them
in?
} > how do I do this without a POST, and have those new fields included
in
} > the request (i guess they need to have a unique name and id).
} >
} > thank you.
} > Alon.
}
} --
} Posted via http://www.ruby-forum.com/.
} _______________________________________________
} Rails mailing list
} Rails@lists.rubyonrails.org
} http://lists.rubyonrails.org/mailman/listinfo/rails
}
1a161d16b292cbacee7b4563bd0c72e8?d=identicon&s=25 goldshuv (Guest)
on 2006-01-23 18:01
Thanks guys,

Well still no luck but I appreciate all the suggestions.

first suggestion (timestamping) gives this:
`@ingredient[Mon Jan 23 18:57:50 IST 2006]' is not allowed as an
instance variable name

second suggestion (arrays) gives this:
undefined method `[]' for :quantity_whole:Symbol

and I can't seem to find this use case (cloning the same form field) in
the bookmark feeds site (but thanks for the source).

still searching...

thanks,
Alon.
97ca2e94ba373515aa387feee67d613e?d=identicon&s=25 Joshua Gitlin (Guest)
on 2006-01-23 18:11
(Received via mailing list)
Hello Everyone,

I hope you AJAX pros don't mind me asking such a simple question, but
it's been baffling me all weekend. I'm trying to learn the AJAX side
of rails and struggling with what I though would be fairly simple
operations. I'd like to add rows to a table, and use an effect, like
Slide Down or Highlight. However, when I tried to add them in the way
recommended by the book I'm going off of, it didn't work. Here's some
snippits of what I have:

My view:
-------------------------------
<% content_for("page_scripts") do -%>
function item_added()
{
	var item = $('mytable').lastChild.lastChild;
	new Effect.Highlight(item);
}
<% end -%>

<h1>Listing</h1>

<%= link_to 'New', :action => 'new' %>

<div id="mytable_div">
<table id="mytable">
<%= render(:partial => 'mytable') -%>
</table>
</div>

<br />
-------------------------------
_mytable.rhtml:
-------------------------------
   <tr bgcolor="#999999">
     <th><font color="#ffffff">Col1</font></th>
     <th><font color="#ffffff">Col2</font></th>
     <th><font color="#ffffff">Col3</font></th>
     <th><font color="#ffffff">...</font></th>
     <th><font color="#ffffff">Col9</font></th>
   </tr>
   <%= render(:partial => 'row', :collection => @items) -%>
-------------------------------
_row.rhtml:
-------------------------------
   <tr bgcolor="#dddddd" id="timecard_<%= timecard.id %>">
     <td><%=h item.val1 %></td>
     <td><%=h item.val2 %></td>
     <td><%=h item.val3 %></td>
     <td>...</td>
     <td><%=h item.val9 %></td>
   </tr>
-------------------------------
Controller's new action:
-------------------------------
   def new
     item = MyClass.new()
     render(:partial => 'row', :object => item, :layout => false)
   end

The row is added by AJAX but no effect is called... any idea what I'm
doing wrong?

-Josh
4005a47a8f2ceee49670b920593c1d52?d=identicon&s=25 Ben Munat (Guest)
on 2006-01-23 18:48
(Received via mailing list)
goldshuv wrote:
> <%= text_field(:ingredient, :name) %>
> <%= text_field(:ingredient, :name) %>
> ...
> ...
>
> and when the form is submitted the request will include only *one* entry
> for ingredient => { name => "sometext"}. and all the text that the user
> entered (besides the first one) will not be there.
>

It is perfectly valid to send multiple values for the same http post
param. Rails should
make that available as an array....

Hmmm, I just went and checked and it appears that Rails only keeps the
first value.
Someone please tell me that I'm just not looking at my @params right...
tell me that rails
is NOT throwing away the other perfectly valid input params! Post params
with the same
name should simply be put into an array.

Hoping someone can set me straight on this!

b
1a161d16b292cbacee7b4563bd0c72e8?d=identicon&s=25 goldshuv (Guest)
on 2006-01-23 19:07
Well, i hope so too, but it's pretty clear from the request dump that
only the first one is saved...

Alon.
4005a47a8f2ceee49670b920593c1d52?d=identicon&s=25 Ben Munat (Guest)
on 2006-01-23 19:46
(Received via mailing list)
Hmm, from the Agile book, pg. 355:

"When the user submits the form, the raw POST data is sent back to our
application. Rails
extracts the fields from the form and constructs the params hash.
*Simple values (such as
the id field, extracted by routing the form action) are stored as
scalars in the hash.
But, if a parameter name has brackets in it, Rails assumes that is it
part of more
structured data and constructs a hash to hold the key values.* Inside
this hash, the
string inside the brackets is used as the key."

So, Rails adds it's own data structure communication nomenclature on top
of basic HTTP.
That's groovy and all, but I personally find it extremely disconcerting
that I have to
bend my html to fit the wishes of rails. And what if -- as was I think
the case of the OP
-- I don't have anything to use as a key... if I'm simply inputting a
list of values?

I don't know if any rails devs are listening here, but I have to say
that I'm fairly
stunned at this oversight. The code handling request params should
simply default to
creating an array for each name found in the headers and wrap this in an
accessor that
returns the first value for single params. It's fine if you want to add
bells and whistles
and allow people to create hashes by putting square brackets in the name
attribute, but it
is a tremendous dent to rails' credibility in my book if it can't handle
multiple params
with the same name.

b
132a94ca65959bda6c74fae54bff2425?d=identicon&s=25 Ezra Zygmuntowicz (Guest)
on 2006-01-23 20:32
(Received via mailing list)
On Jan 23, 2006, at 10:46 AM, Ben Munat wrote:

>
> name found in the headers and wrap this in an accessor that returns
> the first value for single params. It's fine if you want to add
> bells and whistles and allow people to create hashes by putting
> square brackets in the name attribute, but it is a tremendous dent
> to rails' credibility in my book if it can't handle multiple params
> with the same name.
>
> b


Ben-

	Of course you can accomplish what you want with rails params system.
Once you understand how it works I'm sure you will see how nice it is
to work with. If you want a list of text_fields to show up in an
array in the params all you need to do is something like this:

<input  name="list[]" type="text" />
<input  name="list[]" type="text" />
<input  name="list[]" type="text" />
<input  name="list[]" type="text" />
<input  name="list[]" type="text" />
<input  name="list[]" type="text" />

	Then the an array of list items will be available in your controller
with params[:list] . Its' really very simple. By using the empty []
array constructor after the name of the field, rails will
automatically recognize this and create an array in the params hash
with a key of :list. So if you entered the following entries into
your six text fields:

field1
field2
field3
field4
field5
field6

	Then the following would be true:

params[:list] == ['field1', 'field2', 'field3', 'field4', 'field5',
'field6']


Hope that clears it up for you.

Cheers-
-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
ezra@yakima-herald.com
337cdd270761e0e6f4356de45b04d388?d=identicon&s=25 Jonathan Viney (jonny)
on 2006-01-23 21:15
You would be better off doing the effect with either RJS, or as a
callback from the ajax request. To do it the second way, add something
like this to the ajax

:complete => visual_effect(:highlight, <<element_id>>)

Or, to do it your way, you should be calling Effect.Highlight with an
id, not an actual element, ie new Effect.Highlight(item.id);. You should
also check that item is actually the correct element with a valid id.
Just use alert(item.id); to quickly check that.

And... to use ajax, your link_to tag should should be link_to_remote:

<%= link_to_remote :update => 'mytable', :position => :bottom , :url =>
{ :action => :new } %>

Cheers, Jonny.

Joshua Gitlin wrote:
> Hello Everyone,
>
> I hope you AJAX pros don't mind me asking such a simple question, but
> it's been baffling me all weekend. I'm trying to learn the AJAX side
> of rails and struggling with what I though would be fairly simple
> operations. I'd like to add rows to a table, and use an effect, like
> Slide Down or Highlight. However, when I tried to add them in the way
> recommended by the book I'm going off of, it didn't work. Here's some
> snippits of what I have:
>
> My view:
> -------------------------------
> <% content_for("page_scripts") do -%>
> function item_added()
> {
> 	var item = $('mytable').lastChild.lastChild;
> 	new Effect.Highlight(item);
> }
> <% end -%>
>
> <h1>Listing</h1>
>
> <%= link_to 'New', :action => 'new' %>
>
> <div id="mytable_div">
> <table id="mytable">
> <%= render(:partial => 'mytable') -%>
> </table>
> </div>
>
> <br />
> -------------------------------
> _mytable.rhtml:
> -------------------------------
>    <tr bgcolor="#999999">
>      <th><font color="#ffffff">Col1</font></th>
>      <th><font color="#ffffff">Col2</font></th>
>      <th><font color="#ffffff">Col3</font></th>
>      <th><font color="#ffffff">...</font></th>
>      <th><font color="#ffffff">Col9</font></th>
>    </tr>
>    <%= render(:partial => 'row', :collection => @items) -%>
> -------------------------------
> _row.rhtml:
> -------------------------------
>    <tr bgcolor="#dddddd" id="timecard_<%= timecard.id %>">
>      <td><%=h item.val1 %></td>
>      <td><%=h item.val2 %></td>
>      <td><%=h item.val3 %></td>
>      <td>...</td>
>      <td><%=h item.val9 %></td>
>    </tr>
> -------------------------------
> Controller's new action:
> -------------------------------
>    def new
>      item = MyClass.new()
>      render(:partial => 'row', :object => item, :layout => false)
>    end
>
> The row is added by AJAX but no effect is called... any idea what I'm
> doing wrong?
>
> -Josh
337cdd270761e0e6f4356de45b04d388?d=identicon&s=25 Jonathan Viney (jonny)
on 2006-01-23 21:24
You should be able to repeat <%= text_field 'ingredient[]', 'name' %> as
many times as you want, and be able access all of them in the params
hash.

Second suggestion:

You shouldn't use :quantity_whole[], I don't think symbols will work
here. Do 'quantity_whole[]' instead.

Gregory:
You are correct, you don't *have* to use ajax, but if you don't you have
to repeat the code used to create the extra field in javascript. Ajax
helps with DRY in this case.

-Jonny.

goldshuv wrote:
> Thanks guys,
>
> Well still no luck but I appreciate all the suggestions.
>
> first suggestion (timestamping) gives this:
> `@ingredient[Mon Jan 23 18:57:50 IST 2006]' is not allowed as an
> instance variable name
>
> second suggestion (arrays) gives this:
> undefined method `[]' for :quantity_whole:Symbol
>
> and I can't seem to find this use case (cloning the same form field) in
> the bookmark feeds site (but thanks for the source).
>
> still searching...
>
> thanks,
> Alon.
4ecb543bcbe929f29ca6baf0ef56e514?d=identicon&s=25 Michael Bannister (michaelb)
on 2006-01-23 21:31
Jonathan Viney wrote:
> You should be able to repeat <%= text_field 'ingredient[]', 'name' %> as
> many times as you want, and be able access all of them in the params
> hash.

Has anyone who's suggested this actually tried it and got it to work?
I've tried repeating a form element with name like 'ingredient[]' and
setting the form to an action/view which simply calls debug(params).  I
only get a single entry in the "ingredient" hash, with an empty key,
like this:

ingredient: !ruby/hash:HashWithIndifferentAccess
  '': !ruby/hash:HashWithIndifferentAccess
    name: ''
    amount: ''
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-01-23 21:45
(Received via mailing list)
On Mon, Jan 23, 2006 at 09:24:19PM +0100, Jonathan Viney wrote:
[...]
} Gregory:
} You are correct, you don't *have* to use ajax, but if you don't you
have
} to repeat the code used to create the extra field in javascript. Ajax
} helps with DRY in this case.

DRY is all well and good, but it can be taken too far. If I can safely
do
something solely on the client side to avoid a server roundtrip (and
make
no mistake, AJAX is still a server roundtrip), I will do it that way
almost
every time. (Note that I said "safely." There are times when it is
inappropriate to execute code on the client side, particularly when it
involves moving too much or sensitive data to the client side and
possibly
back or when doing so could allow bad data to be accepted by the
server.)

Furthermore, the JavaScript solution I gave degrades nicely on browsers
with JavaScript turned off or entirely unavailable. When the page is
loaded
there is always a blank row for the user to add another line. If
JavaScript
is available, a button is created that will dynamically add another
blank
row. Any rows left blank are ignored by the controller code, but if that
original blank row is filled then the controller will accept it as
another
row. The user with JavaScript can add several rows between server
roundtrips, but the user without JavaScript can still add one row per
server roundtrip. Once you start relying on AJAX, you start making it
harder to degrade nicely.

} -Jonny.
--Greg
4005a47a8f2ceee49670b920593c1d52?d=identicon&s=25 Ben Munat (Guest)
on 2006-01-23 21:48
(Received via mailing list)
Ezra Zygmuntowicz wrote:
>  Its' really very simple. By using the
> empty []  array constructor after the name of the field, rails will
> automatically recognize this and create an array in the params hash
> with a key of :list.

Thanks Ezra. I see that that does indeed work. For the record, I think
it is quite silly
of rails to require empty square brackets just to know that it's got an
array. Seems like
someone was thinking PHP when they decided that. ;-)

Speaking of which, I think this wiki page is out of date:

http://wiki.rubyonrails.org/rails/pages/Understand...


"That this works seems only logical, because in PHP array[] syntax is
used to push new
elements to an array.

However, this is not possible in Rails, so youâ??ll have to improvize by
inputting arrays
with explicit indices. Although it must be admitted that the PHP
notation is very
convenient, you can do the same thing and more with explicit indices in
Rails."

b
This topic is locked and can not be replied to.