Skip to content

Instantly share code, notes, and snippets.

@runspired
Last active January 1, 2016 13:49
Show Gist options
  • Save runspired/8153442 to your computer and use it in GitHub Desktop.
Save runspired/8153442 to your computer and use it in GitHub Desktop.
Fighting Ember-Data to get a related record from the store.
/*
When traversing record.eachRelationship in Ember-Data you
may want to actually look up and include the record if it
is already in the store.
Unfortunately, when dealing with records that are being saved
get(record,attribute) may or may not return the record even if
it is in the store.
If the ID were a temporary ember one (i.e. `<ember-234:null>`)
then get typically results in the record being returned.
BUT
It may also return
-a numeric id as an int
-a numeric id, as a string
-null as null
-null as 'null'
-an array
get is Ember.get
_store is a reference to the store passed in to the parent method
*/
//option 1: hasRecordForId
var lookupRecord = function(parent,relationship){
//usually this will be an existing record
var relatedRecord = get(parent,relationship.key),
type = relationship.type.typeKey
;
if( !isNaN(Number(relatedRecord)) ) {
//check that there is a record in the store
if( _store.hasRecordForId(type, relatedRecord) ) {
//grab the record
relatedRecord = _store.recordForId(type,relatedRecord);
}
}
return relatedRecord;
}
/*
Option 1 is a shorthand for weeding out objects, arrays,
and non numbery strings.
You might think option 1 above would be solid (it isn't, string
'null' IDs turn out to have all sorts of bizzare return behavior).
*/
//option 2: dirtiest simple test
var lookupRecord = function(parent,relationship){
//usually this will be an existing record
var relatedRecord = get(parent,relationship.key),
type = relationship.type.typeKey
;
if( relatedRecord == parseInt(relatedRecord,10) ) {
//check that there is a record in the store
if( _store.hasRecordForId(type, relatedRecord) ) {
//grab the record
relatedRecord = _store.recordForId(type,relatedRecord);
}
}
return relatedRecord;
}
/*
Option 2 works and is the shortest test that passes all our tests.
But it is difficult to see clearly why it works. Option 2 works
because when parseInt(val,10) is called on an array, object, or non
number string it will return NaN, while for a numberish string it
will return that string recast as an int. int 1 == '1' because ==
does not enforce type but instead recasts the types of the objects
it is checking. Understanding everything that is going on makes
this difficult to maintain.
*/
//option 3: maintainably clear test
var lookupRecord = function(parent,relationship){
//usually this will be an existing record
var relatedRecord = get(parent,relationship.key),
type = relationship.type.typeKey,
isNumericId = function(id){
return id !== null && id !== 'null' && !isNaN(Number(id));
}
;
if( isNumericId(relatedRecord) ) {
//check that there is a record in the store
if( _store.hasRecordForId(type, relatedRecord) ) {
//grab the record
relatedRecord = _store.recordForId(type,relatedRecord);
}
}
return relatedRecord;
}
/*
Instead of relying on murky type conversion underneath, we separate
out null and 'null' as individual tests, and use our shorthand for
filtering out anything that isn't numberish for the rest.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment