Changes with DS.RESTAdapter?

Hi!

I have the following model

App.User = DS.Model.extend
  name: DS.attr('string')
  lastName: DS.attr('string')
  email: DS.attr('string')
  admin: DS.attr('boolean')
  active: DS.attr('boolean')
  posts: DS.hasMany('post')
  comments: DS.hasMany('comment')

My json returns this:

{
  "id": 1,
  "name": "Eduardo",
  "last_name": "Figarola",
  "email": "myemail@gmail.com",
  "admin": true,
  "active": true,
  "comments": []
}

When I try to do this:

user.get('lastName')

I get a null value. But if I do something like this:

user.get('_data.last_name')

I see the proper value, is there a new naming convention for model attributes and JSON api? I want to highlight that the previous code was working before I updated to Ember.js 1 and Ember Data 1.0.0-beta.1

Thanks for your help!

I just changed the Rails serializer to return the following JSON:

 {
   "id": 1,
   "name": "Eduardo",
   "lastName": "Figarola Mota",
   "email": "lalo.diabulux@gmail.com",
   "admin": true,
   "active": true,
   "comments": []
 }

And it worked, is this the new convention?

Kinda. Before the beta, the documentation was saying that you should use camel case, but if you called it using underscore, it worked too. But now they just handle camel case.

@wycats added some stuff to TRANSITION.md to explain this case, sorta. Basically, you need to subclass the RESTSerializer and modify it to use the old conventions:

ActiveModelSerializer = DS.RESTSerializer.extend
  # Camelize keys and accept _id and _ids for associations.
  normalize: (type, property, hash) ->
    normalized = {}

    for own prop, value of hash
      if prop.substr(-3) is '_id' # belongsTo relationships
        normalizedKey = prop.slice(0, -3)
      else if prop.substr(-4) is '_ids' # hasMany relationship
        normalizedKey = Ember.String.pluralize(prop.slice(0, -4))
      else # regular attribute
        normalizedKey = prop

      normalizedKey = Ember.String.camelize(normalizedKey)
      normalized[normalizedKey] = value

    @_super(type, property, normalized)

  # Underscore keys and use _id and _ids for associations.
  serialize: (record, options) ->
    json = {}

    record.eachAttribute (name) ->
      json[name.underscore()] = record.get(name)

    record.eachRelationship (name, relationship) ->
      if relationship.kind is 'hasMany'
        key = name.singularize().underscore() + '_ids'
        json[key] = record.get(name).mapBy('id')
      else
        key = name.underscore() + '_id'
        json[key] = record.get(name + '.id')

    json.id = record.get('id') if options?.includeId

    json

App = Em.Application.create({ ApplicationSerializer: ActiveModelSerializer })

You also need to do something similar with the RESTAdapter to ensure that your API is called using underscore_names consistently:

ActiveModelAdapter = DS.RESTAdapter.extend
  namespace: {{whatever}}

  # Always use underscore_names in URLs.
  rootForType: (type) ->
    decamelized = Em.String.decamelize(type)
    Em.String.pluralize(decamelized)

App.ApplicationAdapter = ActiveModelAdapter

Note that this code is for the current HEAD, not the shipped release.

1 Like

@nragaz Thanks for these code snippets!

@wycats @tomdale What are we expecting the default to be here? If we want the default to be sans _id(s) then maybe we should make that the default in active_model_serializers as well, assuming that’s still the preferred way to produce JSON for ember via Ruby/Rails. On a side note, it seems like development on AMS has stagnated waiting for spastorino to finish refactoring on his fork.

A few notes for the other folks new to Ember:

  1. Instead of creating my own “ActiveModelSerializer”, I took @nragaz code and did the following:

    App.ApplicationSerializer = DS.RESTSerializer.extend({ /* etc. */ });

  2. Instead of creating my own ActiveModelAdapter, I merely reopened the DS.RESTAdapter.

The combination of the two steps got me back up and running. Whether or not this is best practice I have to defer to the more experienced on this forum.

The signature for the normalize method changed tonight, so here’s an updated snippet:

ActiveModelSerializer = DS.RESTSerializer.extend
  # Camelize keys and accept _id and _ids for associations.
  normalize: (type, hash, property) ->
    normalized = {}

    for own prop, value of hash
      if prop.substr(-3) is '_id' # belongsTo relationships
        normalizedKey = prop.slice(0, -3)
      else if prop.substr(-4) is '_ids' # hasMany relationship
        normalizedKey = Ember.String.pluralize(prop.slice(0, -4))
      else # regular attribute
        normalizedKey = prop

      normalizedKey = Ember.String.camelize(normalizedKey)
      normalized[normalizedKey] = value

    @_super(type, normalized, property)

  # Underscore keys and use _id and _ids for associations.
  serialize: (record, options) ->
    json = {}

    record.eachAttribute (name) ->
      json[name.underscore()] = record.get(name)

    record.eachRelationship (name, relationship) ->
      if relationship.kind is 'hasMany'
        key = name.singularize().underscore() + '_ids'
        json[key] = record.get(name).mapBy('id')
      else
        key = name.underscore() + '_id'
        json[key] = record.get(name + '.id')

    json.id = record.get('id') if options?.includeId

    json

ActiveModelAdapter = DS.RESTAdapter.extend
  namespace: {{your namespace}}

  rootForType: (type) ->
    decamelized = Em.String.decamelize(type)
    Em.String.pluralize(decamelized)


App = Em.Application.create
  ApplicationAdapter: ActiveModelAdapter
  ApplicationSerializer: ActiveModelSerializer

@jherdman I don’t think it matters which way you go – I like to define the adapter and serializer separately, but that’s just a preference.

1 Like

@nragaz thanks. You may want to make input to Bradley Priest’s pull request:

Basic DS.ActiveModelSerializer implementation

https://github.com/emberjs/data/pull/1206

2 Likes

@yyy Thanks for pointing that out! For my backend I just needed to extend DS.ActiveModelSerializer instead of DS.RESTSerializer - no need to manually configure camelization, etc.