Navigation Menu

Skip to content

Commit

Permalink
Merge pull request #102 from DouweM/keydestination
Browse files Browse the repository at this point in the history
Add `keyDestination` option to complement `keySource`
  • Loading branch information
PaulUithol committed Apr 6, 2012
2 parents b902cf2 + 6d59955 commit 66419d7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 10 deletions.
18 changes: 16 additions & 2 deletions README.md
Expand Up @@ -146,13 +146,27 @@ For example, a Rails backend may provide the keys suffixed with `_id` or `_ids`.

1. When a relation is instantiated, the contents of the `keySource` are used as it's initial data.
2. The application uses the regular `key` attribute to interface with the relation and the models in it; the `keySource` is not available as an attribute for the model.
3. When calling `toJSON` on a model (either via `Backbone.sync`, or directly), the data in the `key` attribute is tranformed and assigned to the `keySource`.

So you may be provided with data containing `animal_ids`, while you want to access this relation as `zoo.get( 'animals' );`.
When saving `zoo`, the `animals` attribute will be serialized back into the `animal_ids` key.

**NOTE**: for backward compatibility reasons, setting `keySource` will set `keyDestination` as well.
This means that when saving `zoo`, the `animals` attribute will be serialized back into the `animal_ids` key.

**WARNING**: when using a `keySource`, you should refrain from using that attribute name for other purposes.

### keyDestination

Value: a string. References an attribute to serialize `relatedModel` into.

Used to override `key` (and `keySource`) when determining what attribute to be written into when serializing a relation, since the server backing your relations may use different naming conventions.
For example, a Rails backend may expect the keys to be suffixed with `_attributes` for nested attributes.

When calling `toJSON` on a model (either via `Backbone.sync`, or directly), the data in the `key` attribute is transformed and assigned to the `keyDestination`.

So you may want a relation to be serialized into the `animals_attributes` key, while you want to access this relation as `zoo.get( 'animals' );`.

**WARNING**: when using a `keyDestination`, you should refrain from using that attribute name for other purposes.

### collectionType

Value: a string (which can be resolved to an object type on the global scope), or a reference to a `Backbone.Collection` type.
Expand Down
9 changes: 5 additions & 4 deletions backbone-relational.js
Expand Up @@ -276,6 +276,7 @@

this.key = this.options.key;
this.keySource = this.options.keySource || this.key;
this.keyDestination = this.options.keyDestination || this.options.keySource || this.key;

// 'exports' should be the global object where 'relatedModel' can be found on if given as a string.
this.relatedModel = this.options.relatedModel;
Expand Down Expand Up @@ -1202,21 +1203,21 @@
var value = json[ rel.key ];

if ( rel.options.includeInJSON === true && value && _.isFunction( value.toJSON ) ) {
json[ rel.keySource ] = value.toJSON();
json[ rel.keyDestination ] = value.toJSON();
}
else if ( _.isString( rel.options.includeInJSON ) ) {
if ( value instanceof Backbone.Collection ) {
json[ rel.keySource ] = value.pluck( rel.options.includeInJSON );
json[ rel.keyDestination ] = value.pluck( rel.options.includeInJSON );
}
else if ( value instanceof Backbone.Model ) {
json[ rel.keySource ] = value.get( rel.options.includeInJSON );
json[ rel.keyDestination ] = value.get( rel.options.includeInJSON );
}
}
else {
delete json[ rel.key ];
}

if ( rel.keySource !== rel.key ) {
if ( rel.keyDestination !== rel.key ) {
delete json[ rel.key ];
}
}, this );
Expand Down
45 changes: 41 additions & 4 deletions test/tests.js
Expand Up @@ -649,7 +649,7 @@ $(document).ready(function() {
ok( person.get( 'user' ).get( 'resource_uri' ) == null );
});

test( "'keySource' loads from & saves to 'key'", function() {
test( "'keySource' loads from 'key", function() {
var Property = Backbone.RelationalModel.extend({
idAttribute: 'property_id'
});
Expand Down Expand Up @@ -689,12 +689,49 @@ $(document).ready(function() {
// The values from view.property_ids should be loaded into view.properties
ok( view.get( 'properties' ) && view.get( 'properties' ).length === 2, "'view' has two 'properties'" );
ok( typeof view.get( 'property_ids' ) === 'undefined', "'view' does not have 'property_ids'" );
});

test( "'keyDestination' saves to 'key'", function() {
var Property = Backbone.RelationalModel.extend({
idAttribute: 'property_id'
});
var View = Backbone.RelationalModel.extend({
idAttribute: 'id',

relations: [{
type: Backbone.HasMany,
key: 'properties',
keyDestination: 'properties_attributes',
relatedModel: Property,
reverseRelation: {
key: 'view',
keyDestination: 'view_attributes',
includeInJSON: true
}
}]
});

var property1 = new Property({
property_id: 1,
key: 'width',
value: 500,
view: 5
});

var view = new View({
id: 5,
properties: [ 2 ]
});

var property2 = new Property({
property_id: 2,
key: 'height',
value: 400
});

var viewJSON = view.toJSON();
ok( viewJSON.property_ids && viewJSON.property_ids.length === 2, "'viewJSON' has two 'property_ids'" );
ok( viewJSON.properties_attributes && viewJSON.properties_attributes.length === 2, "'viewJSON' has two 'properties_attributes'" );
ok( typeof viewJSON.properties === 'undefined', "'viewJSON' does not have 'properties'" );

console.log( view, viewJSON, property1, property2 );
});

test( "'collectionOptionsCallback' sets the options on the created HasMany Collections", function() {
Expand Down

0 comments on commit 66419d7

Please sign in to comment.