With Rails 2.3.2, I found this while writing an AJAX form to
update a users email address.
When using remote_form_for, the prototype helper method properly
appends onto the partial when you initially click "Update Email"
link. The resulting form updates as expected. BUT, when you fill
out the form incorrectly (the user resource doesn't not pass
validation, could be anything, the specific validator doesn't
appear to matter) and the controller reloads the form, it
improperly terminates the form after the first wrapped div and then
renders the submit button useless because the input tags are now
outside of the form tag!
The form works properly by using form_for tag so I see this as a
defect in the remote_form_for helper. Details below:
_show_email.html.erb
<p><b>Email Address: </b><span id="email_target"><%=h @user.email%><%= link_to_remote 'Update Email', :update=>'email_target', :url=>{:controller=>'users', :action=>'edit_email_ajax'} %></span></p>
_edit_email.html.erb
<% remote_form_for(@user, :update=>'email_target',:url=>{:controller=>'users', :action=>'update_email_ajax'}) do |f| -%>
<p><%= f.error_messages %></p>
<p><label for="email">Email</label><br/>
<%= f.text_field :email %></p>
<p><label for="email_confirmation">Confirm Email</label><br/>
<%= f.text_field :email_confirmation %></p>
<p><%= f.submit 'Submit' %></p>
<%end -%>
user_controller.rb snippet
def edit_email_ajax
@user = current_user
render :partial=>'edit_email'
end
def update_email_ajax
@user = current_user
if @user.update_attributes(params[:user])
render :partial=>'show_email'
else
render :partial=>'edit_email'
end
end
rendered HTML code from form without errors - notice the /form
tag is at the end in its proper place.
<form action="/users/update_email_ajax" class="edit_user" id="edit_user_1" method="post" onsubmit="new Ajax.Updater('email_target', '/users/update_email_ajax', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;"><div style="margin: 0pt; padding: 0pt;"><input name="_method" value="put" type="hidden"><input name="authenticity_token" value="bcedBLfJCarXCWIGJ85gjGAaO5Q7hUKinqowlWou2iI=" type="hidden"></div> <p></p>
<p><label for="email">Email</label><br>
<input id="user_email" name="user[email]" size="30" value="phonk64@gmail.com" type="text"></p>
<p><label for="email_confirmation">Confirm Email</label><br>
<input id="user_email_confirmation" name="user[email_confirmation]" size="30" type="text"></p>
<p><input id="user_submit" name="commit" value="Submit" type="submit"></p>
</form>
rendered HTML when the user has errors - notice the end form tag
is found after the error explanation box, which then renders the
Submit tag not working properly on the page since it is outside of
the form tag block now.
<form action="/users/update_email_ajax" class="edit_user" id="edit_user_1" method="post" onsubmit="new Ajax.Updater('email_target', '/users/update_email_ajax', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
<div style="margin: 0pt; padding: 0pt;"><input name="_method" value="put" type="hidden"><input name="authenticity_token" value="bcedBLfJCarXCWIGJ85gjGAaO5Q7hUKinqowlWou2iI=" type="hidden"></div><p></p>
<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>Email address is invalid. Ex: example@examples.com</li></ul></div>
</form>
<p><label for="email">Email</label><br>
</p><div class="fieldWithErrors"><input id="user_email" name="user[email]" size="30" value="phonk64gmail.com" type="text"></div>
<p><label for="email_confirmation">Confirm Email</label><br>
<input id="user_email_confirmation" name="user[email_confirmation]" size="30" value="" type="text"></p>
<p><input id="user_submit" name="commit" value="Submit" type="submit"></p>
</span></code>
Has anyone seen this? An easy workaround is to just not use AJAX
and use form_for since it behaves properly, but of course I'd
rather use AJAX :)