Last active
January 1, 2016 13:49
-
-
Save runspired/8153442 to your computer and use it in GitHub Desktop.
Fighting Ember-Data to get a related record from the store.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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