0

m is a subclass of Backbone.Model. I would expect m.url() to return '/api/media/sources/1' but instead I get:

> m.id
1
> m.collection.url
"/api/media/sources"
> m.urlRoot
undefined
> m.url()
"/api/media/sources"

What's going on?

elplatt
  • 3,227
  • 3
  • 18
  • 20

1 Answers1

1

When you want the id to be appended to the URL, you should set urlRoot, not url.

Take a look at the default implementation for Backbone.Model.prototype.url and it will make sense:

url: function() {
  var base =
    _.result(this, 'urlRoot') ||
    _.result(this.collection, 'url') ||
    urlError();
  if (this.isNew()) return base;
  return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
},

Later comments revealed (after this answer was posted) that the problem had to do with how the attributes were being set.

In general, you should always use model.set("id", idValue) for all attribute changes, even and especially the ID attribute. (If you have set idAttribute to something else on the model prototype, use that name as the first argument instead of "id".)

More generally still, it's a bad idea to access model.attributes directly- use model.set() and model.get() instead. The model.id property is a convenience that you should basically treat as read-only; Backbone will modify it appropriately in every set() call that involves the id attribute. – Platinum Azure 18 hours ago

Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
  • Ah, collection.url should work just as well as urlRoot, but this code shows the real problem: the id is not appended if isNew() returns true. Even though m.id was set, m.attributes.id wasn't, and it turns out you need to set both. – elplatt Aug 28 '14 at 21:11
  • Ah, yes. In general, you should always use `model.set("id", idValue)` for all attribute changes, even and especially the ID attribute. (If you have set `idAttribute` to something else on the model prototype, use that name as the first argument instead of `"id"`.) – Platinum Azure Aug 29 '14 at 02:38
  • And in general, it's a bad idea to access `model.attributes` directly- use `model.set()` and `model.get()` instead. The `model.id` property is a convenience that you should basically treat as read-only; Backbone will modify it appropriately in every `set()` call that involves the id attribute. – Platinum Azure Aug 29 '14 at 02:41
  • Yes, model.id is what confused me, I was trying to set it directly. Now that I set() it, things work as expected. – elplatt Aug 29 '14 at 15:33