?

Log in

Previous Entry | Next Entry

Ruby on Rails :with and Form.serialize

While looking for a way to make an asynchronous request onBlur, I came upon the :with option, which can be used with Form.serialize to pass form data into (among others) the "holy ajax trinity" methods (form_remote_tag, link_to_remote, and remote_function) without a form submit.

I couldn't find any documentation on this powerful trick¹, so I wanted to write some. I'm a terrible doc writer (you get out of practice when you write self-documenting code), so here's an example instead:

We're building a new form to post a job, and within it is a "form" that lets you add tags to the job, one at a time, without submitting the big form. To get around the messiness of nested <form>s, I created an ajax call that makes it look like the server is saving your tags in a database somewhere and displaying the result, but really it was just an excuse to use rjs to append the tags to a list on the client-side. Nothing's really saved until you submit the job form². It looks somewhat like this³:

link_to_remote "save tags",
               :url => { ... },
               :with => "Form.serialize($('form_tags').form)",
               [etc]

Here's the magic of :with. I'm saying: to execute this ajax request you'll need the contents of this form, which I'm sending as POST params*. On the controller side, you now have access to all form values, in params[:form]. For instance, I wanted to get the comma-separated list of tags into an array, which is as easy as:

@tags = params[:form][:tags].split(",")

Hopefully this will be of use to someone else. Using :with and Form.seralize, you can asynchronously pass the contents of the form to server without "submitting" anything.

¹ Try searching for stuff like "rails form :with" or "link_to_remote with" and see the quality of the results. Google Code Search didn't help either.
² Since until you submit the job itself, there's no entity with which to associate the tags.
³ In the following code, form_tags is the DOM id of the tag field...but there's probably a cleaner way to pass the form element into Form.serialize.
* (Ran out of &sup;s) Form.serialize produces a URL-encoded string that is nearly identical to the one that would be sent if you submitted the form (no images, etc. caveat emptor)

Comments

( 6 comments — Leave a comment )
(Anonymous)
Dec. 30th, 2006 11:31 pm (UTC)
This did help...
I was one of the I'm sure many that were lost searching Google for such examples. Glad I stumbled onto your blog! Thanks.
bostonsteamer
Dec. 31st, 2006 05:40 am (UTC)
Re: This did help...
You're welcome!
daybyter
Apr. 20th, 2007 03:14 pm (UTC)
Does this work with Mozilla 2?
Hi!

I'm trying something far more simple: pass one form field in the URL, but it seems that Mozilla 2 simply ignores the :with argument here. And according to

http://railsmanual.com/module/ActionView::Helpers::PrototypeHelper/link_to_remote

(scroll down to the last post)

, it seems I'm not the only one with this problem.

My link is:
=======================
<%= periodically_call_remote( :frequency => "10",
:url => { :action => 'fetch' },
:with => "'last_posting_id='+document.chat_post_form.last_posting_id.value",
:success => "updateChatPostings(request)") %>
=======================
(want to fetch some chat postings and want to pass the id of the last fetched post, so the server only returns newer postings).

Ciao,
Andreas
bostonsteamer
Apr. 20th, 2007 05:04 pm (UTC)
Re: Does this work with Mozilla 2?
Hi Andreas,

That was actually what I was trying to do (pass only one field) but I was also having trouble getting it to work, so I just sent the whole form. I figured it was only an additional 1k of bandwidth.

I guess in your case, the chat will continually get longer and longer, so that might not be an option for you? Sorry I can't be of any more help.

Joe
daybyter
Apr. 21st, 2007 08:29 am (UTC)
Re: Does this work with Mozilla 2?
The chat postings are not part of the form, so the form has a constant length. The idea is to poll every x seconds for new postings and to send the id of the last posting. So I poll for new postings and get message 1,2 and 3. The next time I poll, I send last_posting_id=3 with the request, so the server should only return the new messages 4,5 and 6 (or whatever was written in the last x seconds).

I already tried various constructs like getElementById forms[] etc, but the error console always says, that the form has no properties, even if the dom inspector shows the form fields.
I'll check 2 more options today. The first idea is the doctype, since I've read somewhere, that mozilla behaves differently with different doctypes. And the other idea are div containers, that might prevent me from accessing the form.
bostonsteamer
Apr. 20th, 2007 05:07 pm (UTC)
Re: Does this work with Mozilla 2?
I just thought of one thing to try. Instead of accessing the DOM element with

document.chat_post_form.last_posting_id

Try using the Prototype shortcut

$('last_posting_id')

Or whatever the DOM id of that field is.
( 6 comments — Leave a comment )

Latest Month

August 2014
S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      
Powered by LiveJournal.com