使用Rails 3的Ajax表单 - 最佳实践?

时间:2011-11-18 15:06:44

标签: ruby-on-rails ajax forms unobtrusive-javascript

什么被认为是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>

为了添加一个很好的效果,我在ajax完成时绑定了一个通用的jQuery.live事件,突出了错误。

$('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:完成事件处理显示

完全不同的解决方案是ajax响应只是呈现纯html和我的自定义ajax:完整处理程序将负责显示表单。处理程序看起来像

$('form').live('ajax:success', function(ev, data, status, xhr) {
  $(this).html(data);
  // and e.g. highlight stuff
  $(this).children('.error_message').fadeIn();
});

那会有用。但是现在如果我的服务器决定不再渲染表单(例如成功注册后),而是重定向到另一个URL或显示模式表单,我应该怎么做。服务器可以响应类似的东西

<script>
   document.location = '/success.blabla/';
</script>

但这是一个很好的解决方案吗?

4。自定义JSON协议

可能一个好的解决方案是使用版本3,但不是简单地用返回的html替换当前表单,我们可以创建一些自定义json协议。这样我们甚至可以让服务器响应像

这样的东西
  1. 首先显示模态(如'注册成功')
  2. 重定向到登录页面
  3. ajax:success处理程序可以检查响应是否是纯html,在这种情况下,它会用html代码替换当前表单。但是如果响应是一个JSON数组,它将处理它,例如服务器响应

    { html: '<%= render :partial => 'something' %>', 
      show_modal:  '<%= render :partial => 'modal_template' %>',
      redirect_after_modal: '/login_page'
    }
    

    ajax:success处理程序可以像

    一样处理它
    $('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表单的方法有很多种。但是你是如何做到这一点的,以及Rails最佳做法是什么?

2 个答案:

答案 0 :(得分:8)

所以,我只能将你的问题归结为jquery,当然,它works in jquery 1.6.4,但是not in jquery 1.7

似乎如果替换DOM中的元素,然后在从原始元素创建的jquery对象上触发事件,1.6.4仍然会在元素原始位置触发事件并允许它向上传播DOM。但是,1.7不会触发元素(这更有意义)。

我刚刚通过jquery 1.7更新日志进行了搜索,果然,以下是纠正此行为的两张票:995110489

要回答关于的最佳做法的问题,我会说,控制你的事件触发的顺序。 jQuery自动执行ajax响应中返回的JS,这意味着你无法控制何时发生。

修改代码的最简单方法是返回HTML部分本身,然后使用jquery将表单替换为ajax:completeajax:success / ajax:error中返回的HTML处理程序。通过这种方式,您可以确保按照您想要的确切顺序进行操作。

要了解如何完成此操作,请尝试阅读[我的文章]:

或者查看the jquery-ujs wiki以获取这些链接等内容。

答案 1 :(得分:0)

不确定你是否还需要它,但是我们在这里用AJAX实现表单

假设我们有一个看起来像

的动作
def new
  @saved_search = SavedSearch.new
new

def create
  if @saved_search.save
    respond_to do |format|
      format.js { render :saved }
    end
  else
    respond_to do |format|
      format.js { render :new }
    end
  end
end

我们有一个看起来像

的表单
# app/views/saved_searches/new.html.erb
<%= form_for @saved_search,  url: saved_searches_path(format: :js), remote: true do |f| %>
  <div class="form">
    <div class="content">
      <div class="field">
        <%= f.label(:name, t(".name_search"), class: "label") %>
        <%= f.text_field(:name, size: "25", autofocus: "autofocus") %>
      </div>

      <div class="clear"></div>
    </div>

    <footer class="clear">
      <div class="left">
        <%= f.button t(".save"), class: "button" %>
      </div>
      <div class="clear"></div>
    </footer>
  </div>
<% end %>

显然,如果某些字段无效,我们希望返回错误。所以这是一个技巧

# app/views/saved_searches/new.js.erb
<%- @saved_search.errors.keys.each do |field| %>
  $('#saved_search_<%= field %>').after("<span class=\"errors\">&nbsp;<%=   @saved_search.errors[field].join(',')  %></span>")
  $('#saved_search_<%= field %>').wrap('<div class="field_with_errors" />');;
<% end %>

这不会制造JQuery绑定或回调,但仍会出现错误。

我现在认为编写一些表单构建器可能是一个好主意,它可以呈现HTML表单,并返回表单字段的JQuery指令,

Rails.configuration.action_view.field_error_proc
考虑到