Ember data - change model URL - ember.js

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

Related

Is it possible to create a nested adapter in EmberJS?

Am I able to nest Ember Data adapters?
For example, say if I have a model //models/site.js with a template //templates/site.hbs and I want to make a custom query() request to ${ENV.APP.API_HOST}/customers/${org}/sites - as per the docs I can simply customise the query() function at //adapters/site.js.
But what if I have a second template at //templates/sites/show.hbs and I need to query a second distinctly different endpoint such as ${ENV.APP.API_HOST}/customers/${org}/sites/${id} (or any other deeply nested data endpoint) can I setup an adapter under //adapters/sites/show.js? I can't seem to achieve that with Ember Data currently.
As far as I know, Ember doesn't support nested endpoints at the moment. Related discussions: 1, 2.
So I was able to customise and fix this by using an ember plugin - https://github.com/amiel/ember-data-url-templates/. It has good documentation and allows you to customise URL segments.
My site adapter
// adapters/site.js
export default ApplicationAdapter.extend({
urlTemplate: '{+host}/api/{apiVersion}v1/customers{/org}/sites{/site}',
queryUrlTemplate: '{+host}/api/{apiVersion}v1/customers{/org}/sites'
});
And my service adapter
// adapters/service.js
export default ApplicationAdapter.extend({
urlTemplate: '{+host}/api/{apiVersion}v1/customers{/org}/services{/service}',
});
Then in my routes I loaded params that were picked up by the URL segments in my adapters thanks to ember-data-url-templates. Using seperate queryRecord() calls with Ember store allowed me to specify the correct endpoints as required.
// routes/sites.js
export default Ember.Route.extend({
model: function(params) {
let siteQuery = this.modelFor('sites');
let org = siteQuery.customer_orgCode;
return RSVP.hash({
site: this.get('store').queryRecord('site', { org: org, site: params.site_id })
});
}
});
// routes/sites/show.js
export default Ember.Route.extend({
model: function(params) {
let siteQuery = this.modelFor('sites');
let org = siteQuery.customer_orgCode;
return Ember.RSVP.hash({
service: this.get('store').queryRecord('service', { org: org, service: params.instance_id })
});
}
});
NB // I've use an RSVP hash as there's likely to be multiple calls for the same model, but you can just return the this.get query as necessary directly to model: as well.

Emberjs - how to remove pluralization of URLs?

I am building an emberjs app and I want to call my REST API for results. I have this code:
App.Post = DS.Model.extend();
App.PostAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1',
host: 'http://myapp.com'
});
And in the controller I have this
post: this.store.find('post')
The problem is that it always calls with "s" added in the end, for example - http://myapp.com/api/v1/posts
How do I remove the plural form from these calls?
You need to override the pathForType method in your adapter.
App.PostAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
var camelized = Ember.String.camelize(type);
return Ember.String.singularize(camelized);
}
});
var inflector = new Ember.Inflector();
inflector.singularize('posts');
Ember put 's' automatically. You need to force it to use singular. Above code tells Ember to request to myapp.com/post when you call this.store.find('post'); otherwise default behaviour will try to send request to myapp.com/posts
I had same issue once upon a time. I could not even found a way to set this behaviour globally. I have repeated this code ( inflector.singularize('posts'); ) for every store.

Different REST url for one model

I have an ember application with a few different models. All bar one model pull data from an api at http://example.com/version1/123/. However, one model needs to pull from http://example.com/version1/dogs/123. Is it possible to add a custom url for one model? I've tried changing my store.js file as follows-
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://example.com/version1/123/'
});
App.Store.registerAdapter('App.Dogs', DS.RESTAdapter.extend({
host: 'http://example.com/version1/dogs/123'
}));
but it hasn't had an effect. Any suggestions?
remove the register adapter and just create a custom adapter for dogs (This might need to be singular)
App.DogsAdapter = DS.RESTAdapter.extend({
host: 'http://example.com/version1/dogs/123/'
});
If I understand the question correctly, something like this should work
App.DogAdapter = DS.RESTAdapter.extend({
host: 'http://example.com/version1/dogs/123'
});
I have it setup personally with namespace over host like this.
App.DogAdapter = DS.RESTAdapter.extend({
namespace: "version1/dogs"
});

Add extra url params per model with 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

DS.Model url not working in ember.js

I'm very, very, very new to Ember :-)
I have a DS.Model where I want to force the extension with .json, for retrieving the data from a Rails Server.
The url from the Server is working, and for I can see in the browser's debugger, the url is not what it's specified in the DS.model url
var App = Ember.Application.create();
App.store = DS.Store.create({
adapter: DS.RESTAdapter.create({url: 'http://127.0.0.1:3000'}),
revision: 8
});
App.Expedient = DS.Model.extend({
url: 'expedients/%#.json',
procedencia: DS.attr('string'),
interessat_nom: DS.attr('string'),
data_signatura_provisional: DS.attr('date')
});
Fetch the expedient manually:
var model2 = App.store.find(App.Expedient, 125000);
Output console:
OPTIONS http://127.0.0.1:3000/expedients/125000 404 (Not Found)
I would like to be this url like this:
http://127.0.0.1:3000/expedients/125000.json
Also I've tried to really change the DS.Model url with another different name like this:
App.Expedient.reopenClass({
url: 'mockurl/%#.json'
});
But the browser's console has the same 'url' as before, I don't know why Ember-Data is not getting the model's url.
thanks!
regards,
ps. I'm aware of the Access-Control-Allow-Origin CORS problem when testing Ajax from two origins
github isn't working right now, for some reason, so I can't look at the source for ember, but I think you can do something like this:
var adapter = DS.RestAdapter.extend({
buildURL: function(record, suffix) {
var s = this._super(record, suffix);
return s + ".json";
})
});
You'll need to plug this your store instead of the default rest adapter.
I just tried this with my RESTAdapter subclass and it's working:
App.WORESTAdapter = DS.RESTAdapter.extend({
...
buildURL: function(record, suffix){
return this._super(record, suffix) + ".json";
}
})
Since you are working with a rails back end would it be easier to adapt your API to the same conventions Ember.data expects? so in your expedientsController#show action:
def show
#expedient = Expedient.find(params[:id])
render json: #expedient
end
As long as your controller is returning the JSON structure Ember expects it should map to your DS.Model see: this ember guide.