Backbone model.destroy()即使正常工作,为什么会调用错误回调函数?

37
我有一个使用 Backbone.js 框架的模型,当用户在模型视图中单击链接时,我试图销毁它。该视图类似于以下内容(这是伪代码,因为它是使用CoffeeScript 实现的,可以在问题底部找到)。
var window.ListingSaveView = Backbone.View.extend({
  events: {
    'click a.delete': 'onDestroy'
  },

  onDestroy: function(event){
    event.preventDefault();
    this.model.destroy({
      success: function(model, response){
        console.log "Success";
      },
      error: function(model, response){
        console.log "Error";
      }
    });
  }
});
当我在浏览器中点击delete链接时,尽管我的服务器记录了关联数据库记录的删除成功并返回200响应,但我总是在控制台中看到Error。当我刷新页面(导致集合从数据库重新渲染)后,我删除的模型将被删除。
有趣的是,当我在错误回调函数中记录response时,它具有状态码200,表示成功,但它还报告了statusText: "parseerror",不知道那是什么意思。我的服务器日志中没有错误。
我做错了什么?
这是服务器的响应:
  Object
    abort: function ( statusText ) {
    always: function () {
    complete: function () {
    done: function () {
    error: function () {
    fail: function () {
    getAllResponseHeaders: function () {
    getResponseHeader: function ( key ) {
    isRejected: function () {
    isResolved: function () {
    overrideMimeType: function ( type ) {
    pipe: function ( fnDone, fnFail ) {
    promise: function ( obj ) {
    readyState: 4
    responseText: " "
    setRequestHeader: function ( name, value ) {
    status: 200
    statusCode: function ( map ) {
    statusText: "parsererror"
    success: function () {
    then: function ( doneCallbacks, failCallbacks ) {
    __proto__: Object

这是与destroy交互的服务器动作(Ruby on Rails)

  # DELETE /team/listing_saves/1.json
  def destroy
    @save = current_user.team.listing_saves.find(params[:id])
    @save.destroy
    respond_to do |format|
      format.json { head :ok }
    end
  end

以下是适用于喜欢 CoffeeScript 的人的实际 Backbone View 实现:

class MoveOutOrg.Views.ListingSaveView extends Backbone.View
  tagName: 'li'
  className: 'listing_save'
  template: JST['backbone/templates/listing_save']
  events:
    'click a.delete_saved': 'onDestroy'

  initialize: ->
    @model.bind 'change', this.render
  render: =>
    renderedContent = @template(@model.toJSON())
    $(@el).html(renderedContent)
    this
  onDestroy: (event) ->
    event.preventDefault() # stop the hash being added to the URL
    console.log "Listing Destroyed"
    @model.destroy
      success: (model, response)->
        console.log "Success"
        console.log model
        console.log response

      error: (model, response) ->
        console.log "Error"
        console.log model # this is the ListingSave model
        console.log response

如果服务器有返回信息的话(可以使用Firebug或其他工具打开响应),你能把它粘贴进来吗? - Stephen
编辑了我的问题以包含回复。 - David Tuite
1
哦。嗯,坦率地说...这不是一个有效的响应。它很可能在等待JSON响应...但你可能没有提供它。我记不清我们在工作中用什么来处理rails了,但类似于to_json而不仅仅是'json'(我不是ruby专家...甚至不是初学者...所以我无法提供更多帮助)。 - Stephen
2
好的,我已经弄清楚了。Backbone似乎期望JSON响应是被销毁的记录的JSON序列化。然而,Rails控制器生成器默认只返回head: ok。我将我的JSON响应更改为render json:@listing_save,其中@listing_save是我刚刚销毁的记录,并且它注册了一个成功。 - David Tuite
你确定你的URL正确吗?我的意思是,在Backbone.Model URL的末尾添加了.json吗?由于你在服务器端进行了检查(respond_to do |format| ... end),你可能没有发送正确的head: ok响应... - Tricote
5个回答

52

@David Tuite 评论:

“好的,我想出来了。Backbone期望JSON响应是刚刚被删除记录的JSON序列化。然而,Rails控制器生成器默认只返回head:ok。我把我的JSON响应改成了render json:@listing_save,其中@listing_save是我刚刚删除的记录,并且它注册了一个成功。”

提醒您,在执行销毁操作时,您不需要返回被销毁模型的完整JSON。您可以返回一个空的JSON哈希表,这样也可以正常工作。只有在保存/更新时才需要返回模型的JSON。


3
好的,你可以得到这些积分。即使我只完成了一半的工作 ;) - David Tuite
backbone对rails的JSON结果非常敏感。 - Mike Li
2
虽然您不必返回模型,但有时这样做确实很好。一个情况下这是一个好的方法,就是当您没有使用destroy的{wait:true}参数时 - 这样,如果操作失败,您可以轻松地重新添加模型到集合中,以保持集合更新。 - Arvid Janson
返回一个空的“null”响应也可以(与200状态代码结合使用)。 - Drejc

19

我遇到了同样的问题。在我的服务器端(delete)方法中(使用java编写),我没有返回任何内容,只返回状态码200/OK(或204/No content)。因此,“parsererror”问题是由于jquery尝试将空响应转换为JSON而导致失败(因为“json”是默认数据类型)。

我的解决方案是改用“text”数据类型,可以在选项中设置:

model.destroy({ dataType: "text", success: function(model, response) {
  console.log("success");
}});

好的发现。谢谢。 - chikamichi
2
我也使用了 model.destroy({contentType: false, processData: false}) - carpeliam

8

由于您不会返回任何内容,因此您的响应必须具有状态码204。由于backbone使用REST接口,因此您应该根据任务返回不同的HTTP状态码。


0

你确定你的URL正确吗?在Backbone.Model URL的末尾添加了.json了吗?由于你在服务器端进行了检查(respond_to do |format| ... end),你可能没有发送正确的head :ok响应。

尝试使用这个destroy Rails方法来测试是否存在问题:

def destroy
  @save = current_user.team.listing_saves.find(params[:id])
  @save.destroy
  head :ok
end

0
使用Slim框架在LAMP服务器上,您可以为DELETE路由(或不返回任何内容的自定义路由)添加响应状态$app->response()->status(204);//204 No Content 这也将Content-Type设置回text/html,以允许空主体。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接