0
votes

I am having a hard time to understand how the model relationships works in ember-data. I understand the concept one to many or one to one or many to many, but I don't understand how to use it properly..

My API is sending me this data :

{
    gameweek: [
        {
          commonID: '23',
          content: 'blablabla',
          game: [
              {
                   commonID: '23',
                   gameID: 4,
                   title: 'first game'
              },
              {
                   commonID: '23',
                   gameID: 8,
                   title: 'second game'
              }
          ]
        },
        {
          commonID: '24',
          content: 'blebleble'
          game: [
              {
                   commonID: '24',
                   gameID: 12,
                   title: 'another game'
              }
          ]
        }
    ]
}

As you can see I receive an array that contain some data and an other array.

I don't really know if how I should create my models, should I have just one model ? or multiple like this ? (correct me if its wrong) :

//gameweek.js
import DS from "ember-data";

export default DS.Model.extend({
    commonID:       DS.attr('string'),
    title:          DS.attr('string'),
    games:          DS.hasMany('game')
});

//game.js
import DS from "ember-data";

export default DS.Model.extend({
    commonID:         DS.attr('string'),
    title:            DS.attr('string'),
    gameweek:         DS.belongsTo('gameweek')
});

I would like to be able to save my arrays in the store and keep the relationships between them.

If I do a this.store.find('gameweek', {commonID: '23'} ); I would like to get also all of the game that are related the gameweek. (the commonID would be the same if they are related).

Do I have to create a custom serializer ?

So many questions, thanks for you help !

=============================

UPDATE :

I tried to extend the DS.RESTSerializer like this :

export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
    extractArray: function( store, type, record ) {
        var gameweek = record.predictions;
        gameweek.forEach(function( entry ) {
            var data = entry.games.map(function(game) {
                return game.gameID;
            });
            entry.games = data;
        });
        record = { prediction: gameweek };
        return this._super( store, type, record );
    }
});

This is mainly replacing my game array by an array of gameID, the new array looks like this :

{
        gameweek: [
            {
              commonID: '23',
              content: 'blablabla',
              game: ["4", "8"]
            },
            {
              commonID: '24',
              content: 'blebleble'
              game: ["12"]
            }
        ]
    }

But I get this error : Error: Assertion Failed: Unable to find transform for 'integer'

I am not sure what to do here.

===================================

UPDATE2:

I tried this too :

//serializers/gameweek.js

import DS from "ember-data";

export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
    primaryKey: 'gameWeekID',
    attrs: {
       game: { embedded: 'load' }
    },
    extractArray: function( store, type, record ) {
        // The array of object isn't at the root structure of the record
        var record = record.predictions;
        record = { prediction: record };
        return this._super( store, type, record );
    }
});

//serializers/game.js
import DS from "ember-data";

export default DS.RESTSerializer.extend({
    primaryKey: 'gameID'
});

I got this error : Error: Assertion Failed: Ember Data expected a number or string to represent the record(s) in the "games" relationship instead it found an object. If this is a polymorphic relationship please specify a "type" key. If this is an embedded relationship please include the "DS.EmbeddedRecordsMixin" and specify the "games" property in your serializer's attrs object.

2
Extend your custom serializer with EmbededRecordMixin then override extractSingle and extractArray method to attach unique IDs to all the games object and call super at the end in these methods. - kushdilip
Inside my games I have the id of the gameweek, but also I already have a uniqueID for the game. I did an extractArray, but I don't really understand how I should do what you mean by attacha unique IDs, since I already have one, how should I attach it to the gameweek ? if you could provide a quick example, that could be great ! - SuperMarco
Sorry I didn't notice that you have unique Id in for games. I'll post a quick working example in sometime. - kushdilip

2 Answers

0
votes

In ember you dont save arrays as models you save objects as models. Ember data expects data back in a certain way so you will need to either do this server side or do it with a serializer.
You can save relationships no problem if your models are set clearly.
In the code below taken from embers site your model is a post. so when you query for a post this is what should be returned. The post has a relationship with comments. posts have many comments and comments belong to posts. In the post model there is the id for each comment that is related to that post and then the comments are included as a separate array. http://guides.emberjs.com/v1.12.0/models/the-rest-adapter/#toc_sideloaded-relationships

{
  "post": {
    "id": 1,
    "title": "Node is not omakase",
    "comments": [1, 2, 3]
  },

  "comments": [{
    "id": 1,
    "body": "But is it _lightweight_ omakase?"
  },
  {
    "id": 2,
    "body": "I for one welcome our new omakase overlords"
  },
  {
    "id": 3,
    "body": "Put me on the fast track to a delicious dinner"
  }]
}

The related model files for the above structure are
app/models/post.js

export default DS.Model.extend({
  title: DS.attr('string'),
  comments: DS.hasMany('comment')
});

app/models/comment.js

export default DS.Model.extend({
  body: DS.attr('string'),
  post: DS.belongsTo('post')
});

I dont know if its just my head or its the end of the day but the above naming and structure layout is very confusing. Can you include a bit more detail or make the details less generic, it might help with trying to figure the data out.

0
votes

You should have separate models for gameweek and game. Ember Data works better with more granular models, rather than trying to deal with model fields which are raw objects. This will make it easy to extend the game model in the future with additional functionality, such as computed properties and validators. So your proposed model structure is fine.

To make this work with your current JSON structure, however, you're going to have to declare that game is embedded. To do that

// serializers/gameweek.js
import ApplicationSerializer from './application';
import DS from 'ember-data';
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
    attrs: {
        games: { embedded: 'load' }
    }
});

We inherit from ApplicationSerializer as best practice so that if it specifies things they are inherited by this model-specific serializer.

In addition, Ember Data is going to insist on a unique id for each game, so it has a way to identify it in the store. If gameId is unique, you can use that as is, but you'll have to let Ember Data know, by saying

// serializers/game.js
import ApplicationSerializer from './application';
import DS from 'ember-data';
export default ApplicationSerializer.extend({
    primaryKey: 'gameId'
});

Once you do this, you will no longer refer to the id as gameId; you will refer to it as id, and you do not need to, and should not, declare it as part of your model.