Add extra url params per model with Ember.js - ember.js

I have two models:
App.Providers = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
logo: DS.attr('string'),
products: DS.hasMany('App.Products')
});
App.Products = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string')
provider: DS.belongsTo('App.Providers'),
});
They are both using the same Adapter. However, for the Products model I want to append an extra url param (the api key) to the url. How can I extend the adapter (or the serializer?) to implement this?
So just to give you an example when I want to do a GET for providers:
http://example.com/ap1/v1/providers/
and for products:
http://example.com/ap1/v1/products/?api_key=1234
I know I can add this when I do App.Products.find({api_key=1234}) but the problem occurs when I do:
var providers = App.Providers.find(1);
providers.get('products');
EDIT:
I have tried to override the buildURL method in the adapter but it's not very convenient since I want to append the api_key param only for certain models.

You should create a second adapter which overrides the buildURL method. Then register that adapter for any types that should be using an api key.
apiAdapter = originalAdapter.extend({
buildURL: ....
}));
Store.registerAdapter(App.Providers, apiAdatper);
See this post for more detail on per-type adapters: How to use DS.Store.registerAdapter

Related

Ember data - change model URL

I am using ember 2.0 and ember-data 2.0, and I have been struggling to find a way to pass custom URL to model.
For example, if my model is named Person and stored in model/person.js file, I would like rest web service url for finding record to be xxx/user/1, or in other words to avoid convention, and pass my URL to rest service - is is possible at all?
You can use Adapter.
If your backend conventions differ from Ember Data convention, it easy to change its functionality by swapping out or extending the default Adapter.
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1',
pathForType: function(type) {
return Ember.Inflector.inflector.singularize(type);
}
});
If you want just override a specific model just write new adapter with modelName + Adapter.
When I want to use a custom adapter for a 'note' model I can do something like:
App.Note = DS.Model.extend({
title: DS.attr('string'),
/* others attrs */
});
App.NoteAdapter = DS.RESTAdapter.extend({
namespace: 'other/endpoint',
pathForType: function(type) {
return Ember.Inflector.inflector.pluralize(type);
}
});
Take a look at ember adapter guide, if you use ember-cli use blueprint generator like:
ember generate adapter user

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.

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

How to add in hasMany relationship with the Ember Data local storage adapter/serializer?

I am using the Ember local storage adapter for an app that has two models: Organizations and Members. The relationship is that Organizations "hasMany" Members, and Members "belongsTo" Organizations, as follows:
App.Org = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
members: DS.hasMany('App.Member')
});
App.Member = DS.Model.extend({
name: DS.attr('string'),
org: DS.belongsTo('App.Org')
});
In the jsbin of the app, you can add members and the organizations to the local storage, which works perfectly (meaning that when I add a new organization, its selected members are added in the "members" hasMany relationship).
In addition to adding the new organization information, I would like to serialize the newly created organization record to be sent over to a server via AJAX (no I not want to use the RESTAdapter).
However, the "members" hasMany relationship is completely missing from the serialization, so this is the serialization that I'm getting (you can see for yourself if you add some members and then open up the console):
{
name: "Organization name",
description: "description of the org"
}
and this is the serialization that I would like:
{
name: "Organization name",
description: "description of the org",
members: ["id_of_member_1", "id_of_member_2", "id_of_member_3"]
}
This is how I am doing the serialization:
App.OrganizationController = Ember.ArrayController.extend({
createOrg: function(){
var neworg = App.Org.createRecord({
name: this.get('newname'),
description: this.get('newdescription')
});
neworg.get('members').pushObjects(this.get('newmembers'));
neworg.save();
var serializer = DS.RESTSerializer.create({});
console.log(serializer.serialize(neworg));
}
...
If serialization is not the way to go, another way might be making "members" a string array attribute, but so far this path has failed me.
In addition to suggestions, please provide a working jsbin based on the current jsbin of the app. Because I've tried things that don't work.
Keep in mind this app is set up with an Ember Data local storage adapter.
You can do it with the DS.EmbeddedRecordsMixin. org-serializer.js would look like:
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
members: { serialize: 'ids' }
}
});
See the documentation here.

Finding record by custom primaryKey

My model is defined as follow:
App.User = DS.Model.extend({
primaryKey: 'username',
username: DS.attr('string'),
name: DS.attr('string')
});
My custom Adapter map:
DS.SocketAdapter.map('App.User', {
primaryKey: 'username',
username: DS.attr('string'),
});
I am testing this model out by typing on console:
App.User.createRecord({username:"user_1"});
var r = App.User.find("user_1");
console.log( r.serialize() );
>> Object {username: null, name: null ..... all null}
But it retuns a "null" Object. Also tested:
App.User.find({username:"user_1"});
But this is doing a remote request. I read that Ember Data does allow you to find records via attributes other than the ID.
So what I am doing wrong in telling Ember data my custom primaryKey?
I think your problem lies in the fact that you are defining username twice. if you map username from your json to your model's primaryKey trough your Adapter, then you should avoid to do the same on the model I guess. There are different approaches where to define the mapping, but the Adapter is the most appropriate place In your case, see here for more details: https://github.com/emberjs/data/blob/master/BREAKING_CHANGES.md#mapping
change your code like so and it should work:
// Model
App.User = DS.Model.extend({
name: DS.attr('string')
});
// Adapter
DS.SocketAdapter.map('App.User', {
primaryKey: 'username'
});
now try to create a new record
App.User.createRecord({username:"user_1", name:"foo"});
and then find the record by it's id as you already did:
var r = App.User.find("user_1");
this
console.log( r.serialize() );
should then give you at least:
>> Object {name: "foo" ...}
hope it helps