在Rails 3应用程序中使用jQuery-UJS进行远程link_to时出现分析错误:我该如何调试?

我在使用Rails 3, remote_link :remote => true和jQuery点击链接后尝试替换div的内容。

到目前为止,我已经能够在使用200 HTTP代码响应时让控制器呈现正确的部分。 我设置了一些回调来找到问题的根源:

 jQuery(function($) { $("#follow-link").bind("ajax:before", function() { console.log("ajax:before"); }); $("#follow-link").bind("ajax:success", function(data, status, xhr) { console.log("ajax:success"); }); $("#follow-link").bind("ajax:complete", function() { console.log("ajax:complete"); }); $("#follow-link").bind("ajax:error", function(xhr, status, error) { console.log("ajax:error"); console.log(error); }); }); 

触发beforecompletesuccess不是, error输出“parsererror”。 我在Safari的开发人员工具中检查响应时得到的内容是一个简单的字符串。

为什么会引发一个parsererror? 如何获得有关导致此错误的更多信息?

我打算提出一个答案,因为评论不允许任何格式化。 这是:服务器端发生了一些事情,而jQuery没有得到你认为的那样。 以下是jQuery文档的摘录:

error(jqXHR,textStatus,errorThrown)function请求失败时要调用的函数。 该函数接收三个参数:jqXHR(在jQuery 1.4.x中,XMLHttpRequest)对象,描述发生的错误类型的字符串和可选的exception对象(如果发生)。 第二个参数的可能值(除了null)是“timeout”,“error”,“abort”和“parsererror”。 发生HTTP错误时,errorThrown会收到HTTP状态的文本部分,例如“未找到”或“内部服务器错误”。

这意味着您的控制器可能正在响应预期数据以外的其他内容。 在该控制器中,尝试:

 Rails.logger.debug render_to_string(:partial => "followings/follow") 

在任何情况下,请检查您的日志,以确保您认为发生的事情真的发生了。 另外,编写一个测试来validation这一点:

 # controller spec... modify if using Test::Unit it "sends cool javascript" do xhr.post :unfollow, :id => 83, :data-method => "delete" response.body should == "some known response" end 

好吧,这是一个hacky,脆弱的规范,但它会做,直到你知道出错的地方。

一旦你开始工作,其他一切都会整齐地落到实处。

即使我的远程链接正确指向以下操作,我也得到奇怪的parsererror :format => :js和我的控制器操作正确使用respond_to来提供JSON对象,如:

 respond_to do |format| format.js do render :json => {:something => "OK"} end end 

解决方案最终只是将这一行放入我的application.js

 $.ajaxSettings.dataType = "json"; 

默认情况下,似乎jQuery试图将所有响应评估为"script" ,我猜这意味着它试图将其作为代码执行 – ? 一次删除此行就可以全局解决问题。

而不是使用全局$.ajaxSettings.dataType = 'json'; 设置更干净的解决方案是向表单元素添加data-type属性。 远程表单事件处理程序将把它作为dataType传递给jQuery AJAX调用,例如:

 form_for @subject, :remote => true, :html => {'data-type' => 'json'} 

而不是format.js使用format.json

设置$.ajaxSettings.dataType = 'json'; 可能会导致代码的其他部分出现问题。

我的解决方案是在控制器中用’.html’而不是’.js’替换响应格式。

它的作用是将响应内容类型发送为“html / text”而不是“html / javascript”,这对响应解析器来说是可接受的。

解决此问题的另一种方法是将.js添加到表单的操作中(如果您使用的是Rails链接生成器,则可以添加:format =>:json)。 然后确保您在控制器中响应json。

以下是以这种方式配置的登录表单的示例:

  <%= form_for User.new, :url => session_path(:user, :format => :json), :html => {:id => "login-form", :class => "well"}, :remote => :true do |f| %>  <%= f.text_field :email %>  <%= f.password_field :password %> <%= f.hidden_field :remember_me %> <%= button_tag "Sign in", :class => "btn", :type => "submit" %><%= image_tag "ajax-loader.gif", :style => "display:none", :id => "login-spinner" %> <% end %> 

在控制器中:

 def create respond_to do |format| format.html{ super } format.json do resource = warden.authenticate!(:scope => resource_name, :recall => :failure) return sign_in_and_redirect(resource_name, resource) end end end 

如果您尝试使用来自rails控制器操作的HTML输出使用正常的JQuery AJAX调用来更新DIV的内容,您需要告诉JQuery在响应上期望什么dataType,以便它不会将响应解析为javascript并给你你描述的parsererror。

 $.ajax({ url: "/blah", contentType: "text/javascript", dataType: "html", beforeSend: function(xhr) { xhr.setRequestHeader('Accept', 'text/javascript'); }, success: function(data) { $('your-div').html(data); } }); 

然后,这将与使用respond_to块的控制器操作兼容:

 respond_to do |format| format.html { # This would be a normal render of your template. } format.js { # This would be a render of your template, as HTML, but only for your AJAX requests. # We might use this to avoid including the layout of our template. render :layout => nil } end