Say I have the following ember-data model:
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
starred: DS.attr('boolean')
});
This communicates with a Rails app with the following pretty standard CRUD API:
GET /people - get a list of people
POST /people - create a new person
GET /people/id - get a specific person
PUT /people/id - update a specific person
DELETE /people/id - delete a specific person
This all maps to Ember-Data with the standard Store/Adapter.
However, lets say that in order to "star" or "unstar" a person, the API doesn't let us do this by the standard update action. There's a specific API endpoint for this action:
POST /people/id/star - mark a person as "starred"
POST /people/id/unstar - mark a person as "unstarred"
How do I fit this API in with Ember Data?
It looks like I'd need to extend DS.Store and DS.RESTAdapter somehow, but I'm not sure of the best approach to make them aware of these different actions. It also feels a bit wrong that a generic Adapter for the app has to be aware of starring people.
Note that I have no control over the API, so I can't make POST /people/id
aware of "starring" so that it would fit in with a standard update.
Been a while and it may not have been possible at the time, but you can call the ajax method of your adapter directly:
YourApp.Store.prototype.adapter.ajax(url, action, {data: hashOfParams})
For example:
YourApp.Store.prototype.adapter.ajax('/products', 'GET', {data: {ids: [1,2,3]}})
For your question:
YourApp.Store.prototype.adapter.ajax('/people' + id + '/star','POST')
Edit - using buildURL is useful, particularly if you've set a namespace on your adapter:
url = YourApp.Store.prototype.adapter.buildURL('people',id) + '/star'
Edit 2 - You can also get the adapter with container.lookup('adapter:application')
, which is useful if you don't have global access to the app (ex ES6 modules / ember-cli)
Edit 3 - The above refers to an outdated version of Ember / Ember-CLI. Now I define this function in a mixin -
customAjax: (method, type, id, action, hash = null) ->
#note that you can now also get the adapter from the store -
#adapter = @store.adapterFor('application')
adapter = @container.lookup('adapter:application')
url = adapter.buildURL(type, id) + '/' + action
hash['data'] = $.extend({}, hash) if hash #because rails
adapter.ajax(url, method, hash).then (result) =>
return result
And call it like so -
@customAjax('PUT', 'modelClass', modelId, 'nonCRUDActionName', optionalHashOfAdditionalData).then (response) =>
#do something with response
I went through the same issue, and solved it using a modified version of what is explained in here: Non-crud rails actions in Ember.js
Basically, you need to use a Jquery AJAX call, the important part for me was to change the contentType in order to get the auth data to be sent in the request headers, rather than in form-data (the default, if you include data in your call). Also, make sure to give the proper context in the AJAX part, otherwise 'this' won't work in the 'success' callback:
App.ItemController = Ember.ObjectController.extend
actions:
starItem: ->
controller = this
item = @get 'model'
id = item.id
token = @auth.get 'authToken'
$.ajax
type: 'PUT'
context: controller
data: '{ "auth_token": "' + token + '"}'
url: '/api/v1/items/' + id + '/star'
contentType: 'application/json; charset=UTF-8'
dataType: 'json'
success: ->
if @get 'item.starred_by_user'
@set 'model.starred_by_user', false
item.decrementProperty('total_stars')
else
@set 'model.starred_by_user', true
item.incrementProperty('total_stars')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With