admin管理员组

文章数量:1391960

My Backbone app municates with an API that exists on another server. Backbone.sync will generate relative URLs by default. The simplest way to prepend the absolute server path would be something like the following:

MyApp.BASE_URL = ""


class MyApp.Model extends Backbone.Model
  urlRoot: "#{MyApp.BASE_URL}/my_app_url"

However, I'd rather not do this as it isn't DRY. I thought I could try something like the following by overriding Backbone.sync:

do (Backbone) ->
  BASE_URL = ''
  baseSync = Backbone.sync

  Backbone.sync = (method, model, options) ->
    url = _.result(model, 'url')
    options.url = "#{BASE_URL}/#{url}" if url && !options.url

    baseSync method, model, options

However, this is problematic for other parts of the code as the options object gets passed around all over the place. *(explanation for the interested at the bottom)

Is there a remended clean and DRY way to prepend a server path to the front of all URLs generated by Backbone.sync?


*If the model being synced is an instance of Backbone.Collection this options object will get passed to the collection's model constructor. URL is one of the few properties that will get directly attached to a model if it is passed in as a part of the options object. This breaks sync for any models that are created in a collection as they now have a set URL attached to them instead of a url method that generates an appropriate url by using urlRoot or the collection's url.

My Backbone app municates with an API that exists on another server. Backbone.sync will generate relative URLs by default. The simplest way to prepend the absolute server path would be something like the following:

MyApp.BASE_URL = "https://api.someOtherSite."


class MyApp.Model extends Backbone.Model
  urlRoot: "#{MyApp.BASE_URL}/my_app_url"

However, I'd rather not do this as it isn't DRY. I thought I could try something like the following by overriding Backbone.sync:

do (Backbone) ->
  BASE_URL = 'https://api.someOtherSite.'
  baseSync = Backbone.sync

  Backbone.sync = (method, model, options) ->
    url = _.result(model, 'url')
    options.url = "#{BASE_URL}/#{url}" if url && !options.url

    baseSync method, model, options

However, this is problematic for other parts of the code as the options object gets passed around all over the place. *(explanation for the interested at the bottom)

Is there a remended clean and DRY way to prepend a server path to the front of all URLs generated by Backbone.sync?


*If the model being synced is an instance of Backbone.Collection this options object will get passed to the collection's model constructor. URL is one of the few properties that will get directly attached to a model if it is passed in as a part of the options object. This breaks sync for any models that are created in a collection as they now have a set URL attached to them instead of a url method that generates an appropriate url by using urlRoot or the collection's url.

Share asked May 14, 2013 at 21:17 AaronAaron 14.1k11 gold badges72 silver badges109 bronze badges 2
  • possible duplicate of Backbone.sync per model – gion_13 Commented May 16, 2013 at 11:40
  • I don't believe this question is asking the same thing. The question you linked to is asking how to have certain models call one sync and have others call another. That could be done by simply overriding the model's sync method so it does not proxy to Backbone.sync. This question is asking how can I globally modify the URL sync calls go to so that they are absolute paths to another server instead of relative ones to the originating server. – Aaron Commented May 16, 2013 at 22:44
Add a ment  | 

3 Answers 3

Reset to default 4

I think the best option is to create a base model that your other models will extend from:

MyApp.Model = Backbone.Model.extend({
  urlRoot: function(){
             return 'https://api.someOtherSite./' + this.get('urlFragment')
  }
});

And then have your models be defined like so

MyApp.MyModel = MyApp.Model.extend({
  urlFragment: "my_model_url"
})

So, in CoffeeScript:

class MyApp.Model extends Backbone.Model
  urlRoot: ->
           'https://api.someOtherSite./' + @get('urlFragment')

And

class MyApp.MyModel extends MyApp.Model
  urlFragment: "my_model_url"

Now you've got your urls specified in a DRY fashion!

You should use prototypes to have a universal property across all collections or models etc.

Backbone.Collection.prototype.absURL  = 'http://example.';

var MyCollection = Backbone.Collection.extend({
model : myModel, 
url: function() {
    return this.absURL + '/api/stuff';
}
});

Know this is old, but I ran into the issue while putting together a client for an api I'm developing. My solution, while dry and very simple, happens in jQuery not Backbone. That said jQuery is a dep of Backbone so I think its a reasonable approach for the typical case.

$.ajaxPrefilter(function prependUrlPrefilter(opts) {
  opts.url = 'http://127.0.0.1:3000' + opts.url;
});

One gotcha with this approach is that it globally mutates the url of any xhr calls running through jQuery. If you're calling web services on multiple domains or you have plugins that do and share your same jQuery you'll need to add a condition here.

Also you'll want to abstract the host portion of the domain to a config.

More can be found on ajaxPrefilters here.

本文标签: javascriptPrepend absolute URL path in Backbonesync for an API on another serverStack Overflow