How to override the primary key with a JSON API at

2019-09-03 19:24发布

问题:

I've got a model called "Membership" that has a string attribute "inviteToken" which I would like to use as my primary key.

I've created the following serializer, but cannot get it to pick up the primary key from the JSON.

app/serializers/membership.js:

import DS from 'ember-data';

export default DS.JSONAPISerializer.extend({
  primaryKey: 'invite-token' // also tried 'inviteToken'
});

The specific error I'm getting is:

Error while processing route: invitations.show Assertion Failed: You must include an 'id' for membership in an object passed to 'push'
Error: Assertion Failed: You must include an 'id' for membership in an object passed to 'push'

Which happens when I try to get a record by its ID in the route:

import Ember from 'ember';

export default Ember.Route.extend({
  model(params) {
    return this.store.find('membership', params.token);
  }
});

API Response:

{
  "jsonapi":{
    "version":"1.0"
  },
  "data":{
    "type":"membership",
    "id":"30",
    "attributes":{
      "invite-token":"5bGo7IhZh93E4SB07VWauw"
    }
  }
}

The strange thing is that if I use "type" as the primary key, I see "membership" as the id in the ember inspector. It's as if ember data doesn't know how to use something from the "attributes". I'm using ember data 2.4.0.

Update

I can hack this to work in my serializer by doing this:

import DS from 'ember-data';

export default DS.JSONAPISerializer.extend({
  normalize: function(type, hash) {
    const json =  this._super(type, hash);
    json.data.id = json.data.attributes.inviteToken;

    return json;
  }
});

回答1:

The serializer expects the value of primaryKey to refer to a top level element in the json. This is why "type" and "id" works. It currently does not support nested properties (for example primaryKey: "attributes.invite-token")

However there are two good workarounds:

The first is overriding the extractId method. The default implementation is quite simple. In your case you could do something like:

extractId(modelClass, resourceHash) {
    var id = resourceHash['attributes']['invite-key';
    return coerceId(id);
  },

The second way is the method you discovered, a more brute force approach, and that is to assign the id manually in the normalize function.