1
votes

I just stumbled on to Ember Data Polymorphic Relationships. I think they would be useful for what I am working on. Here is my main model. This model defines a has many relationship with topics thats both async and polymorphic.

App.Source = DS.Model.extend({
    name: DS.attr('string'),
    type: DS.attr('string'),
    locationType: DS.attr('string'),
    locationSpecific: DS.attr('boolean'),
    primary: DS.attr('boolean'),
    published: DS.attr('boolean'),
    sort: DS.attr('number'),
    topics: DS.hasMany('topic', {
        async: true,
        polymorphic: true
    })
});

Next we have the Topics with a Base class being 'Topic'

App.Topic = DS.Model.extend({
    name: DS.attr('string'),
    sort: DS.attr('number'),
    source: DS.belongsTo('source')
});

App.RegTopic = App.Topic.extend({
    test: DS.attr('number', {
        defaultValue: 8
    }),
    notes: DS.hasMany('notes', {
        async: true
    })
});

App.SummaryTopic = App.Topic.extend({
    number: DS.attr('number', {
        defaultValue: 9
    })
});

and here is how I call to get the topics

App.TopicsRoute = Ember.Route.extend({
     model: function() {
           return this.modelFor('source').get('topics');
     }
});

When I list the sources, I get a list of the following objects back

 {
         id: 1
         name: "test"
         type: "testType"
         locationType: "international"
         locationSpecific: "true"
         primary: true
         published: true
         sort: 1
         links: {
                 topics: "/topics?sourceId=1"
         }
    }

then my topic call gets objects like these back

{
   id: 4
   sourceId: 1
   name: Topic 4
   type: "regTopic"
   sort: 1
}

Am I missing something? Can you not use polymorphic relationships with the 'links' object?

From my understanding of the Polymorphic Relationship, when I make the call to /topics?sourceId=1 its should be essentially loading 2 different topics in one call so then I can display the regTopic and summaryTopic on the same page but in seperate lists and keep them as seperate objects?

Here is an updated jsbin, that seems close to working. http://emberjs.jsbin.com/medojitibo/1/edit?html,js,console,output

The issue I am seeing it that in my controller, the topics are all App.Topic in the list. There is no App.RegTopic or App.SummaryTopic

2
1. What exactly is the problem? 2. Please provide a demo of the issue via emberjs.jsbin.comAndrey Mikhaylov - lolmaus

2 Answers

0
votes

The links element looks like JSON-API, for which there is an addon. I have had to make modifications for polymorphism in my fork. It may be easier to modify your back-end to support the API specified by Ember Data.

0
votes

I would not recommend using Ember Data polymorphism unless you really know what you are doing and have convinced yourself it does what you need. Currently it's designed for fairly limited use cases. There are a number of discussions and proposals on the topic that you can track down if you are interested.

You apparently believe, or the API believes, that the format for the links property in the JSON for the source object is an object containing a single (?) topics property which gives the API endpoint for retrieving a polymorphic topic. That's not how it works at all.

The correct syntax for the links property in the returned JSON would be an array of {id, type} tuplets:

{
    id: 1
    name: "test"
    type: "testType"
    ...
    links: [
        { id: 'topic1', type: 'regTopic'},
        { id: 'topic2', type: 'summaryTopic' }
    ]
}

The format of the data for the association, as shown above, is an array of id/type objects, rather than just an array of ids. This is required for Ember Data polymorphism to work. If you can't arrange for your back-end to produce exactly this kind of format, you will end up patching and hacking a number of methods in adapters and serializers and at the end of the day building your own version of polymorphism, probably not an endeavor you wish to embark on.

Without this special form of JSON for the association properties, Ember Data has no idea of what type of object to go looking for. With it, Ember Data will create the proper instance type of topic for each entry in this topics array, and essentially make a call to find('reg-topic', 'topic1') and find('summary-topic', 'topic2') to get its data. That means that you will also need a separate API endpoint for each subtype of topic. (Matters differ if the topics are embedded, an alternative I won't go into here.)

So far so good, perhaps. But this starts to break down quickly once you start to do more sophisticated things. Let's say you want to fetch/retrieve a topic with a particular ID. One might think that since "topics are polymorphic", you could just do this.store.get('topic', id). But you can't. The store holds RegTopics and SummaryTopics in separate places, and does not connect them with Topic. If you ask for a 'Topic', it does not know to look under different (sub-)models for instances already in the store. So you have to know in advance what the type is and ask the store for the record of that particular type, which sort of defeats the whole purpose of polymorphism. If you simply call the topics endpoint, Ember Data will create a new model instance for Topic--it has no idea that it is supposed to examine the type field of the returned JSON to govern what subtype to turn it into.

The point is that here topics are not polymorphic. In Ember Data polymorphism is not at the model level; it's at the association level. What is polymorphic here, in other words, is not the topic model itself; it's the associations held in the links property on the source model. In other words, Ember Data has no idea about a model itself being polymorphic; it just knows that particular association (hasMany or belongsTo) can hold polymorphic values. For some insights into what might be required to make Ember Data truly support polymorphic models, albeit in a slightly different context, take a look at https://github.com/Bestra/ember-data-sti-guide.

To answer your question in your comment, no, Ember Data polymorphism is not the best way to do what you want. Do not venture out into these uncharted waters. I'd adopt a strategy of "poor man's polymorphism", where your Topic model has a type field, and might or might have some different properties depending on the type. You can then sort and group and filter on type to your heart's content.