سؤال

I have a Backbone.js model that I'm trying to destroy when the user clicks a link in the model's view. The view is something like this (pseudocode because it's implemented in CoffeeScript which can be found at the bottom of the question).

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";
      }
    });
  }
});

When I click the delete link in the browser, I always get Error logged to the console even though my server records successful destruction of the associated database record and returns a 200 response. When I refresh the page (causing the collection to re-render from the DB) the model I deleted will be gone.

One interesting this is that when I log the response in the error callback, it has statuscode 200 indicating success but it also reports statusText: "parseerror" whatever that means. There is no error in my server logs.

What am I doing wrong?

This is the response from the server:

  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

Here is the server action that destroy interacts with (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

And here is the actual CoffeeScript implementation of the Backbone View for people who prefer it like that:

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
هل كانت مفيدة؟

المحلول

@David Tuite comment:

"Ok I figured it out. It seems that Backbone expects the JSON response to be a JSON serialization of the record that was destroyed. However, Rails controller generators only return head :ok by default. I changed my JSON response to be render json: @listing_save where @listing_save is the record I just destroyed and it registers a success."

FYI - when you're doing a destroy, you don't need to return the full json for the destroyed model. you can return an empty json hash and it will work just fine. the only time you need to return the json for the model is on a save / update.

نصائح أخرى

I had this same problem. In my delete method on the server (java), I didn't return anything. Just status 200/OK (or 204/No content). And so the "parsererror" problem was caused by jquery trying to convert the empty response into JSON, which failed (since "json" is the default data type).

My solution was to use the "text" dataType instead, which can be set in the options:

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

Your response must have status code 204 as you won't return any content. Since backbone uses a REST interface you should return different http status codes depending on the task.

Are you sure of your URL ? Do you append a .json at the end of the Backbone.Model url ? Since you check this on your server side (respond_to do |format| ... end), you might not send the correct head :ok response

Try with this destroy rails method to test if this is the problem :

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

Using the Slim Framework on an LAMP server you can add a Response Status to DELETE routes (or custom routes that don't return anything)

$app->response()->status(204);//204 No Content

this also sets the Content-Type back to text/html to allow for the empty body

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top