Ajax Forms with Rails 3 - 最佳实践?
什么是 Ajax 表单的 Rails 方式
直到今天,我还认为使用 Rails 表单 + jQuery UJS 的方式是正确的方式,但是升级到 jQuery 1.7 “打破了”我迄今为止的方式。
如何做到这一点?
我想在我的表单中使用 Ajax。 ajax 响应应该再次呈现表单(例如,当发生错误时)或重定向到成功页面。 (它也许应该做更多的事情,比如显示模态,但我想让这个例子保持简单)。
1. 使用 EJS 和 $('#formid').html(...)
这就是我迄今为止所做的。我的 ajax 响应是一个 ejs 模板,它返回 javascript 代码以再次呈现表单(有错误),或者根据是否是错误将用户重定向到成功页面:
<% unless @success_submit %>
$('#form_wrapper').html('<%= escape_javacsript( render :partial => 'form' ) %>');
<% else %>
document.location = '/success_thank_you';
<% endif %>
现在假设表单包含一个错误消息 div,例如
<div class="error_message">BlaBla</div>
要添加一个不错的效果我有一个通用的 jQuery.live 事件绑定在 ajax 完成上,它突出显示了错误。
$('form').live('ajax:complete', function() {
// do stuff like highlighting all error messages in that form
});
这不再适用于 jQuery1.7 + jquery-ujs (可能有充分的理由)。所以我觉得我的做法不对。
2.使用上面的方法,但重复我自己,
而不是绑定 ajax:complete 事件,我可以在 EJS 中执行“错误突出显示的内容”,例如
$('#form_wrapper').html('<%= escape_javascript( render :partial => 'form' ) %>');
$('#form_wrapper form .error_message').fadeIn();
但这意味着我必须在几乎每个呈现表单的 EJS 中重复第二行。当然,我想保持干燥。
3. Ajax 响应呈现纯 html,ajax:complete 事件处理显示
一个完全不同的解决方案是 ajax 响应仅呈现纯 html,而我的自定义 ajax:complete 处理程序将负责显示表单。处理程序看起来
$('form').live('ajax:success', function(ev, data, status, xhr) {
$(this).html(data);
// and e.g. highlight stuff
$(this).children('.error_message').fadeIn();
});
会起作用。但是现在,如果我的服务器决定不再渲染表单(例如在成功注册后),而是重定向到另一个网址或显示模式表单,我该怎么办?服务器可以响应类似的内容,
<script>
document.location = '/success.blabla/';
</script>
但是这是一个好的解决方案吗?
4. 自定义 JSON 协议
也许一个好的解决方案是使用版本 3,但我们可以创建一些自定义 json 协议,而不是简单地用返回的 html 替换当前表单。这样我们甚至可以让服务器响应诸如
- 首先显示模式(如“注册成功”)
- 重定向到登录页面的
内容ajax:success 处理程序可以检查响应是否是纯 html,在这种情况下它将用以下内容替换当前表单html 代码。但如果响应是一个 JSON 数组,它会处理这个问题,例如服务器响应
{ html: '<%= render :partial => 'something' %>',
show_modal: '<%= render :partial => 'modal_template' %>',
redirect_after_modal: '/login_page'
}
一样处理它
$('form').live('ajax:success', function(ev, data, status, xhr) {
// try parsing json
if (data.json['show_modal') { // show modal code.... };
if (data.json['redirect']) { document.location=data.json['redirect']);...
});
ajax:success 处理程序会像How are you do this stuff
显然,处理 ajax 表单的方法有很多。但是你是如何做到的,以及 Rails 的最佳实践是什么?
What is considered the Rails Way for Ajax Forms
Until today I thought the way I use Rails forms + jQuery UJS was the right way to do it, but the upgrade to jQuery 1.7 'broked' the way I did it so far.
How to do this?
I want to use Ajax with my forms. The ajax response should either render the form again (e.g. when errors occur) or redirect to a success page. (It should maybe do more, like showing modals, but I want to keep this example simple).
1. Using EJS and $('#formid').html(...)
That is what I did until to date. My ajax response was an ejs template which returned javascript code to render the form again (with errors) or depending if it was an error redirected the user to success page:
<% unless @success_submit %>
$('#form_wrapper').html('<%= escape_javacsript( render :partial => 'form' ) %>');
<% else %>
document.location = '/success_thank_you';
<% endif %>
Now imagine the form contains an error message div like
<div class="error_message">BlaBla</div>
To add a nice effect I had a general jQuery.live event bound on ajax complete which highlighted errors.
$('form').live('ajax:complete', function() {
// do stuff like highlighting all error messages in that form
});
That doesn't work with jQuery1.7 + jquery-ujs anymore (probably by good reasons). So I guess the way I did it was not right.
2. Using above way but repeat myself
Instead of binding the ajax:complete event I could do the "error highlighting stuff" in the EJS like
$('#form_wrapper').html('<%= escape_javascript( render :partial => 'form' ) %>');
$('#form_wrapper form .error_message').fadeIn();
But that would mean I would have to repeat the second line in almost each EJS which renders forms. And of course I want to keep it DRY.
3. Ajax response renders pure html, ajax:complete event handles display
A complete different solution would be that the ajax response simply would render pure html and my custom ajax:complete handler would take care of displaying the form. The handler would look like
$('form').live('ajax:success', function(ev, data, status, xhr) {
$(this).html(data);
// and e.g. highlight stuff
$(this).children('.error_message').fadeIn();
});
That would work. But now what should I do if my server decides not to render the form again (e.g. after successful signup) but instead redirect to another url or showing a modal form. The server could respond with something like that
<script>
document.location = '/success.blabla/';
</script>
But is that a good solution ?
4. Custom JSON protocol
Probably a good solution would be to use version 3 but instead of simply replacing the current form with the returned html we could create some custom json protocol. That way we could even let the server respond with stuff like
- first show modal ( like 'Signup Success')
- redirect to login page
The ajax:success handler could check if the response is pure html, in that case it would replace the current form with the html code. But if the response is a JSON array it would handle that, e.g. server responds with
{ html: '<%= render :partial => 'something' %>',
show_modal: '<%= render :partial => 'modal_template' %>',
redirect_after_modal: '/login_page'
}
The ajax:success handler would have handle it like
$('form').live('ajax:success', function(ev, data, status, xhr) {
// try parsing json
if (data.json['show_modal') { // show modal code.... };
if (data.json['redirect']) { document.location=data.json['redirect']);...
});
How are you doing this stuff
Obviously there are many ways how you handle ajax forms. But how are you doing it, and what is considered best practice with Rails ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
所以,我只能将你的问题归结为jquery,果然,它适用于jquery 1.6.4< /a>,但jquery 1.7 中没有。
看起来,如果您替换 DOM 中的元素,然后在从原始元素创建的 jquery 对象上触发事件,1.6.4 仍然会在元素原始位置触发事件并允许其向上传播 DOM。然而,1.7 不会触发该元素(这更有意义)。
我刚刚搜索了 jquery 1.7 变更日志,果然,这里有两张纠正此行为的票证: 9951 和 10489。
为了回答您关于完成此类事情的最佳实践是什么的问题,我会说,控制事件的触发顺序。 jQuery 自动执行 ajax 响应中返回的 JS,这意味着您无法控制何时发生。
修改代码的最简单方法是返回 HTML 部分本身,然后使用 jquery 将表单替换为
ajax:complete
或ajax:success
中返回的 HTML >/ajax:error
处理程序。这样您就可以确保事情按照您想要的顺序发生。要了解具体如何完成此操作,请尝试阅读[我的文章]:
或者参见 jquery-ujs wiki 了解这些链接及更多内容。
So, I was able to boil your issue down to jquery only, and sure enough, it works in jquery 1.6.4, but not in jquery 1.7.
It seems that if you replace an element in the DOM, and then trigger an event on the jquery object created from the original element, 1.6.4 would still trigger the event in the elements original location and allow it to propagate up the DOM. 1.7, however, will not trigger the element (which makes more sense).
I just did a search through the jquery 1.7 changelog and sure enough, here are the two tickets which rectified this behavior: 9951 and 10489.
To answer your question about what is the best practice for accomplishing something like this, I would say, take control over what order your events fire. jQuery automatically executes JS returned in ajax responses, which means you have no control over when that happens.
The easiest way to modify your code would be to return the HTML partial itself, and then use jquery to replace the form with the returned HTML in the
ajax:complete
orajax:success
/ajax:error
handlers. This way you can be sure that things happen in the exact order you want.To see how exactly to accomplish this, try reading [my articles]:
Or see the jquery-ujs wiki for these links and more.
不确定您是否还需要它,但是这里我们使用 AJAX 实现表单做了什么
假设我们有一个看起来像这样的操作
,并且我们有一个看起来像这样的表单
显然,如果某些字段无效,我们希望返回错误。所以这里有一个技巧
,它不会阻止 JQuery 绑定或回调,但仍然会向您显示错误。
我现在认为编写一些表单生成器可能是一个好主意,它既能够渲染 HTML 表单,又能返回表单字段的一堆 JQuery 指令,考虑
到这一点
Not sure if you need it anymore, but here what we have done to implement forms with AJAX
Suppose we have an actions that looks like
and we have a form that looks like
And, obviously, we want to return an errors if some fields are invalid. So here is a trick
That does not brake JQuery bindings or callback, but still presents you with errors.
I am now thinking that it might be a good idea to write some form builder, that will be able both render an HTML form, and return bunch of JQuery directives for form fields, taking
into consideartion