Backbone.js Модель разные URL для создания и обновления? - PullRequest
31 голосов
/ 04 января 2012

Допустим, у меня есть модель Backbone, и я создаю экземпляр модели, подобной этой:

var User = Backbone.Model.extend({ ... });
var John = new User({ name : 'John', age : 33 });

Интересно, возможно ли это, когда я использую John.save() для цели /user/create, когда я используюJohn.save() во второй раз (обновление / PUT) для цели /user/update, когда я использую John.fetch() для цели /user/get и когда я использую John.remove() для цели /user/remove

Я знаю, что могопределять John.url каждый раз перед тем, как запускать какой-либо метод, но мне интересно, может ли это произойти автоматически, каким-то образом без переопределения любого метода Backbone.

Я знаю, что мог бы использовать один URL-адрес, такой как /user/handle, и обрабатыватьзапрос основан на методе запроса (GET / POST / PUT / DELETE), но мне просто интересно, есть ли способ иметь другой URL для действия в Backbone.

Спасибо!

Ответы [ 5 ]

78 голосов
/ 04 января 2012

Методы .fetch(), .save() и .destroy() при Backbone.Model проверяют, определена ли модель .sync() и если даон будет вызван в противном случае Backbone.sync() будет вызван (см. последние строки связанного исходного кода).

Таким образом, одно из решений заключается в реализации метода .sync().

Пример:

var User = Backbone.Model.extend({

  // ...

  methodToURL: {
    'read': '/user/get',
    'create': '/user/create',
    'update': '/user/update',
    'delete': '/user/remove'
  },

  sync: function(method, model, options) {
    options = options || {};
    options.url = model.methodToURL[method.toLowerCase()];

    return Backbone.sync.apply(this, arguments);
  }
}
2 голосов
/ 31 января 2014

Чтобы абстрагироваться от решения dzejkej еще на один уровень, вы можете обернуть функцию Backbone.sync, чтобы запросить у модели URL-адреса для конкретного метода .

function setDefaultUrlOptionByMethod(syncFunc)
    return function sync (method, model, options) {
        options = options  || {};
        if (!options.url)
            options.url = _.result(model, method + 'Url'); // Let Backbone.sync handle model.url fallback value
        return syncFunc.call(this, method, model, options);
    }
}

Тогда вы можете определить модель с помощью:

var User = Backbone.Model.extend({
    sync: setDefaultUrlOptionByMethod(Backbone.sync),
    readUrl: '/user/get',
    createUrl: '/user/create',
    updateUrl: '/user/update',
    deleteUrl: '/user/delete'
});
1 голос
/ 04 января 2012

Вы имеете дело с реализацией REST, которая не требует спецификаций или требует какого-то обходного пути?

Вместо этого рассмотрите вариант использования emulateHTTP, найденный здесь:

http://documentcloud.github.com/backbone/#Sync

В противном случае вам, вероятно, просто потребуется переопределить метод Backbone.sync по умолчанию, и вам будет хорошо, если вы захотите по-настоящему сойти с этим ... но я этого не советую.Лучше всего использовать настоящий интерфейс RESTful.

0 голосов
/ 09 октября 2014

Меня вдохновило это решение, где вы просто создаете свой собственный вызов ajax для методов, которые не предназначены для извлечения модели. Вот его урезанная версия:

var Backbone = require("backbone");
var $ = require("jquery");
var _ = require("underscore");

function _request(url, method, data, callback) {
  $.ajax({
    url: url,
    contentType: "application/json",
    dataType: "json",
    type: method,
    data:  JSON.stringify( data ),
    success: function (response) {
      if ( !response.error ) {
        if ( callback && _.isFunction(callback.success) ) {
          callback.success(response);
        }
      } else {
        if ( callback && _.isFunction(callback.error) ) {
          callback.error(response);
        }
      }
    },
    error: function(mod, response){
      if ( callback && _.isFunction(callback.error) ) {
        callback.error(response);
      }
    }
  });
}

var User = Backbone.Model.extend({

  initialize: function() {
    _.bindAll(this, "login", "logout", "signup");
  },

  login: function (data, callback) {
    _request("api/auth/login", "POST", data, callback);
  },

  logout: function (callback) {
    if (this.isLoggedIn()) {
      _request("api/auth/logout", "GET", null, callback);
    }
  },

  signup: function (data, callback) {
    _request(url, "POST", data, callback);
  },

  url: "api/auth/user"

});

module.exports = User;

И тогда вы можете использовать его так:

var user = new User();

// user signup
user.signup(data, {
  success: function (response) {
    // signup success
  }
});

// user login
user.login(data, {
  success: function (response) {
    // login success
  }
});

// user logout
user.login({
  success: function (response) {
    // logout success
  }
});

// fetch user details
user.fetch({
  success: function () {
    // logged in, go to home
    window.location.hash = "";
  },
  error: function () {
    // logged out, go to signin
    window.location.hash = "signin";
  }
});
0 голосов
/ 04 января 2012

Нет, вы не можете сделать это по умолчанию с магистралью. То, что вы могли бы сделать, это добавить в модель, которая будет изменять URL модели при каждом событии триггера модели. Но тогда у вас всегда есть проблема, что bckbone будет использовать POST добавить при первом сохранении модели и PUT для каждого последующего вызова. Поэтому вам необходимо переопределить метод save() или Backbone.sync.

В конце концов, кажется, что это не очень хорошая идея, потому что она нарушает структуру REST, на которой построен Backbone.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...