How to get the response data of a save with Ember Data?


#1

I’m using Ember.js with ember-data to make a GUI for a self made API.

I’ve been following this tutorial to handle authentication but I want to use ember-data instead of custom jQuery requests.

One thing I have to do is to call the API to create a new session, by sending email and password, and the API sends me back an API Key object.

Here is my LoginController handling the loginUser action (it’s CoffeeScript) :

App.LoginController = Ember.ObjectController.extend
  actions:
    loginUser: ->
      session = @store.createRecord 'session',
        email:    @get 'email'
        password: @get 'password'
      session.save()

Here is the result I get when creating a session:

{
    "users": [
        {
            "id": "525fa0286c696c0b14040000",
            "email": "john.doe@mydomain.com",
            "first_name": "John",
            "surname": "Doe"
        }
    ],
    "api_key": {
        "id": "526e464c6c696c07d2000000",
        "type": "session",
        "key": "6b824d6a-a065-4b6f-bb28-5c19389760f8",
        "expires_at": "2013-10-28T11:41:08+00:00",
        "user_id": "525fa0286c696c0b14040000"
    }
}

I have Session, ApiKey and User models. I can create the session, but the thing I don’t understand is how to access the return value of the save() method.

I know that my ApiKey and User are loaded somewhere because I get an error after save() if their respective Ember model don’t exist but I don’t know how to access them.

I’ve tried to use save() callbacks like then() or didCreate event but there’s a lack of documentation about arguments passed to these callbacks and how to use them.

  • Ember.js 1.1.2
  • Ember Data 1.0.0.beta.3

EDIT: I’ve tried to create an actuel Session model on my API, resulting in this JSON output:

{
    "api_keys": [
        {
            "id": "526f69526c696c07d2110000",
            "type": "session",
            "key": "4c26af37-2b21-49c2-aef5-5850a396da0b",
            "expires_at": "2013-10-29T08:22:50+00:00",
            "user_id": "525fa0286c696c0b14040000"
        }
    ],
    "users": [
        {
            "id": "525fa0286c696c0b14040000",
            "email": "john.doe@coreye.fr",
            "first_name": "John",
            "surname": "Doe"
        }
    ],
    "session": {
        "id": "526f6e666c696c18c0010000",
        "api_key_id": "526f69526c696c07d2110000"
    }
}

(note the root element is now session)

It doesn’t work better because now my save action leads to the following error (not in the console but then points to error callback):

Object function () { [...] } has no method 'eachTransformedAttribute'

I get this error, the relation between Session and ApiKey being declared in Ember Data models or not…


#2

save returns a promise that is going to be resolved or rejected when the server tries to save the object.

In case the save is successful, the fulfilledHandler is going to receive the data returned by the server as its argument:

App.LoginController = Ember.ObjectController.extend
  actions:
    loginUser: ->
      session = @store.createRecord 'session',
        email:    @get 'email'
        password: @get 'password'
      session.save (data) ->
        # Handle data.users and data.api_key here

In truth, the docs are not very specific on that one.


#3

Are you sure about session.save (data) -> ?

This provides the function as an argument to save…which doesn’t take arguments…

save()'s promise is supposed to be used with then() like this:

  session.save().then ((session) -> 
    # Handle success
  ), ((error) ->
    # Handle error
  )

But the session variable, which is an actual Session model instance, doesn’t provide my api_key…


#4

Sorry, you are right. I meant to write

App.LoginController = Ember.ObjectController.extend
  actions:
    loginUser: ->
      session = @store.createRecord 'session',
        email:    @get 'email'
        password: @get 'password'
      session.save().then (data) ->
        # Handle data.users and data.api_key here

If data in your fulfiller function does not have a top-level api_key key, I’m out of ideas, unfortunately.


#5

Ok, that’s what I’ve tried but data.api_key and data.get('api_key') are empty.

I think the good solution could be to return the api key embedded into an actual Session object but it’s even worse (see my edit).

The strange thing is that returning a session object with an Id will successfully set the id todata.get('id'), but if I return the session with an api_key reference, then I have a Object function () { [...] } has no method 'eachTransformedAttribute' error…


#6

@Porecreat, did you ever figure anything out here? I am in a similar situation.


#7

For anyone else who comes across this, my solution was to override the adapter (create method in my case), have the adapter call the _super function with the same parameters it receives, and then access the “side-loaded” data (users and api_key in this case) attached to data on .then(function(data) {}) of the _super.create call. The whole thing together might look something like the following:

App.SessionAdapter = DS.ActiveModelAdapter.extend
  createRecord: (store,type,record) ->
    @_super(store,type,record).then((data) ->
      data.users
      data.api_key
    )

Depending on what you would want to do, you should be able to store.push the data.users and data.api_key records into the store or whatever else.