backbone-associations
backbone-associations copied to clipboard
Different keys for lookup and relation referencing
I am thinking about similar attributes Relational has key
and keySource
This perfectly matched our data/server communication before.
Example. Here is project object
{"id": 10, "name": "Project"}
And this is task:
{"id": 20, "name": "Task", "pid": 10}
pid
- is id of a project this task belongs to. So I naturally do something like this
class Task extends Backbone.AssociatedModel
relations: [{
type: Backbone.One
relatedModel: 'model.Project'
key: 'pid'
map: (pid) ->
someGlobalScope.projects.get pid
}]
But now, I can access project from Task only by task.get('pid')
- But this is wrong. pid is Project Id, not project itself. I would like to task.get('project')
Is there a way?
Don't know if this is should be requested here, but ...
In the example above, when we want to store Task back to the server, we want to send information about project it belongs to. And this is also defined with pid
property.
Right now I can define serialize: ['id']
, but this will make
{"id": 20, "name": "Task", "pid": {"id": 10}}
which is not what I wanted =\ I thought what if serialize
could be not only Array, but a string also. In case of string it could make what I want for example. Also this will makes IN and OUT to be consisted (Which is logical I think) (I mean what was passed as raw JSON string in the beginning will come back the same)
Something like this would work maybe?
===================================================================
--- app/components/backbone-associations/backbone-associations.js (revision )
+++ app/components/backbone-associations/backbone-associations.js (revision )
@@ -260,21 +259,22 @@
// if `relations` are available.
_.each(this.relations, function (relation) {
var relationKey = relation.key,
+ referenceKey = relation.referenceKey || relation.key,
activationContext = relation.scope || root,
relatedModel = this._transformRelatedModel(relation, attributes),
collectionType = this._transformCollectionType(relation, relatedModel, attributes),
map = _.isString(relation.map) ? map2Scope(relation.map, activationContext) : relation.map,
- currVal = this.attributes[relationKey],
+ currVal = this.attributes[referenceKey],
idKey = currVal && currVal.idAttribute,
val, relationOptions, data, relationValue, newCtx = false;
// Merge in `options` specific to this relation.
relationOptions = relation.options ? _.extend({}, relation.options, options) : options;
- if (attributes[relationKey]) {
+ if (attributes[referenceKey]) {
// Get value of attribute with relation key in `val`.
- val = _.result(attributes, relationKey);
+ val = _.result(attributes, referenceKey);
// Map `val` if a transformation function is provided.
val = map ? map.call(this, val, collectionType ? collectionType : relatedModel) : val;
And now my relation definition looks like
relations: [{
type: Backbone.One
relatedModel: 'Project'
key: 'project'
referenceKey: 'pid'
isTransient: true
map: (id) ->
toggl.model.Projects.get id
}]
In result. I get project on .get('project')
I get id on .get('pid')
and this id still in the JSON response
Looks like if I set new project task.set 'pid', 'test2'
it also works well.
I ran into a similar situation. Without modifying Backbone Associations, you could do this more easily. In your original example you wrote this:
class Task extends Backbone.AssociatedModel
relations: [{
type: Backbone.One
relatedModel: 'model.Project'
key: 'pid'
map: (pid) ->
someGlobalScope.projects.get pid
}]
You could do the following to get your desired result without any modifications to the lib.
class Task extends Backbone.AssociatedModel
relations: [{
type: Backbone.One
relatedModel: 'model.Project'
key: 'project'
map: ->
someGlobalScope.projects.get @get 'pid'
}]