Ember data override foreign key convention - ember.js

I am trying to load json data into the following model using findAll:
App.Territory = DS.Model.extend({
name: DS.attr('string'),
code: DS.attr('string'),
regionId: DS.attr('string')
});
When the model is actually created, converting back to JSON shows that it has a reference for region_id, which is null, but nothing for regionId. Does anyone know of a way to override this default convention?

Determined that it was the keyForAttribute method on the RESTSerializer that was calling Ember.String.decamelize(name) which formated the key. I was able to work around this by adding the line:
App.store.adapter.serializer.keyForAttributeName = function (type, name) {
return name;
}

Related

Initializing and passing an ember.js model/object?

export default Ember.Route.extend({
model: function() {
return this.store.all('foo');
}
});
I want to use store.all instead of store.find, correct, since I don't want to load the contents from HTTP?
Then:
models/foo
export default DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
Or should I not be using a model, and an Ember Object instead? The docs for initializing an object say to use App.Foo.Create(), but AFAIK ES6 modules have gotten rid of the App namespace?
Ultimately I want to define a model, then pass that to a component and edit the values. After which I'll save each instance of that created model until I need to do something with them.
Pseudo code of what I'm trying to accomplish:
var model = {
key: "value"
}
export default model
controller/router:
import model from 'model'(?)
this.model = model;
template.hbs:
{{my-component data=model}}

How to overwrite ember-data reader method? or convert DS.attr to computed property? similar to backbone parse

I have an endpoint that returns id, name, properties, and properties is a damn string, with comma separated attribute key/value pairs. Yes you read that correctly.
properties = "id:1,name:foobar,phone:123456789,taco:true"
Current Model
import DS from 'ember-data';
export default DS.Model.extend({
contact: DS.belongsTo("contact"),
name: DS.attr(),
phone: DS.attr(),
properties: DS.attr(),
eachProperties: function () {
return this.get('properties').split(",").map(function(propertyKeyValuePair) {
return propertyKeyValuePair.split(":");
});
}.property('properties')
});
properties requires some computation to be helpful on the front-end.
Can you re-use the property named properties instead of creating a new one called eachProperties?
Something like:
export default DS.Model.extend({
// ... other stuff
properties: DS.attr(function(model, obj){
return obj.split(",").map(function(propertyKeyValuePair) {
return propertyKeyValuePair.split(":");
});
});
});
OR how does one change the name of an api property name to something else like rawProperties and then have the computed property called properties?
I know you're thinking "Just fix your damn API" but you know that isn't always possible :)
After some research, I found that i basically wanted to utilize Transforms (docs) to handle the deserializing. Its super easy and rad.
As per Ember-CLI module-directory-naming-structure, you add transforms inside the app/transforms/ folder.
I created a file called properties.js. (Whatever you name the file will be the name of attribute/transform.)
//*inside app/transforms/properties.js*
import DS from 'ember-data';
export default DS.Transform.extend({
deserialize: function (serialized) {
return serialized.split(",").map(function (keyValuePair) {
return keyValuePair.split(":");
});
},
serialize: function (deserialized) {
return deserialized.map(function (keyValuePair) {
return keyValuePair.join(":");
}).join(",");
}
});
This transform will be used when you receive json, and also when you send the JSON back out! super cool.
Updated Model:
import DS from 'ember-data';
export default DS.Model.extend({
contact: DS.belongsTo("contact"),
name: DS.attr('string'),
phone: DS.attr(),
properties: DS.attr('properties')
});
the DS.attr('properties') is where the magic happens!

Ember data embedded has one relationship for ember-data.1.0.0

I am trying to serialize a user object and pass it to an ember client. My app uses the RESTserializer.
A user object has_one address object. There is no separate endpoint for just the address so I can't just provide a foreign key id and sideload it.
The JSON received just includes address as an object and looks something like this:
{"user":
{
"id":"5",
"name":"Andrew",
"address":
{
"id":"3",
"addressable_id":"5",
"street":"1",
"country_code":"US"
}
}
On the ember side I have a user model
App.User = DS.Model.extend({
name: DS.attr('string'),
address: DS.belongsTo('address'),
//hasOne via belongsTo as suggested by another SO post:
//http://stackoverflow.com/questions/14686253/how-to-have-hasone-relation-with-embedded-always-relation
});
and an address model
App.Address = DS.Model.extend({
addressable_id: DS.attr('string'),
street: DS.attr('string'),
country_code: DS.attr('string'),
user: DS.belongsTo('user')
});
Currently running this code throw an error in the console:
TypeError: Cannot read property 'typeKey' of undefined
which can be fixed by removing the
address: DS.belongsTo('address'),
line in the user model but then the relationship doesn't load properly.
So what am I doing wrong configuring this? I am having a hell of a time finding up to date documentation on this.
You need to use the DS.EmbeddedRecordsMixin on a per-type serializer.
In your case, you would need to do the following :
App.UserSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
address: {embedded: 'always'}
}
});
as explained in this excellent answer.

EmberData belongsTo not working with just ID

I am trying to create a belongsTo relation, but i am always getting the following error:
Error while loading route: Error: Assertion Failed: You must include
an id in a hash passed to push
My model definition looks like this:
GambifyApp.Bet = DS.Model.extend({
scoreT1: DS.attr('string'),
scoreT2: DS.attr('string'),
user: DS.belongsTo('user')
});
Within my Json return I have simply
{
id:128433,
user:8926,
points:0,
game:94,
scoreT1:2,
scoreT2:2
}
The user value under user is my user id. Regarding Documentation(http://emberjs.com/guides/models/the-rest-adapter/#toc_relationships) it should look exactly like this. But its causing me this error. If I change my "user" property to an attribute everything is working fine.
Update:
Found the problem in my serializer that is extracting all relations and adds them as sideloaded models. Of course it was not handling the case where this relation is only an id instread of the whole object.
If you aren't including the data associated with user the relationship should be async.
GambifyApp.Bet = DS.Model.extend({
scoreT1: DS.attr('string'),
scoreT2: DS.attr('string'),
user: DS.belongsTo('user', {async:true})
});

Ember Data Endpoint Issue

I am experiencing a weird issue while using ember data. With the following user model everything works great.
App.User= DS.Model.extend({
firstName: attr(),
lastName: attr()
});
I call user.save() and is posts to /users with the correct data. However when i try and use a user model that has relationships on it
App.User= DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
friends: DS.hasMany('user'),
followers: DS.hasMany('user'),
});
For some reason with that model when i call user.save() it posts to /Users (note the capitalization. Also, in the response it expects it formatted {"User": {...}} instead of {"user": {...}}
Anyone run into this before? I could always add the additional endpoints to my api however I would like it to work uniform if possible.
I did a little more digging and it seems when you add a relationship to the model there is a computed property called relationshipsByName. This property, in my example, will set the meta.type property to 'User'. It works without relationships because I called the createRecord method with 'user' so i assume it uses this as the type. When the relationship is added it uses 'User'
I found that modelFor calls the resolvers normalize on the keys. So the solution is to add a custom resolver like below.
App = Ember.Application.create({
Resolver: Ember.DefaultResolver.extend({
normalize: function(fullName) {
var n = this._super(fullName);
if(fullName.startsWith('model')){
n = n.replaceAt(6, n[6].toLowerCase());
}
return n;
}
})
});
*note i have string extensions for startsWith and replaceAt