Multilevel relationships and sideloaded data


#1

Hi all - this is a repost of a stack overflow question as I’m trying to find more ember eyes, so my apologies if this isn’t acceptable. Just let me know and I’ll close one of them…

I have an app that has many layers of relationships. I have a Tournament with n rounds, each round has n matchups, each matchup has n seats, each seat has 1 entry. Here’s a sample of the json structure:

{
  "tournament": {
    "id":                     1,
    "title":                  "March Madness!!!",
    "rounds":                 [1],
    "active_round":           1
  },
  "rounds": [
    {
      "id":         1,
      "tournament": 1,
      "matchups":   [1, 2]
    },
    {
      "id":         2,
      "tournament": 1,
      "matchups":   [3]
    }
  ],
  "matchups": [
    { "id": 1, "round": 1, "seats": [1, 2] },
    { "id": 2, "round": 1, "seats": [3, 4] },
    { "id": 3, "round": 2, "seats": [5, 6] }
  ],
  "seats": [
    { "id": 1, "matchup": 1, "entry": 1 },
    { "id": 2, "matchup": 1, "entry": 2 },
    { "id": 3, "matchup": 2, "entry": 3 },
    { "id": 4, "matchup": 2, "entry": 4 },
    { "id": 5, "matchup": 3, "entry": "" },
    { "id": 6, "matchup": 3, "entry": "" }
  ],
  "entries": [
    { 
      "id":               1,
      "seats":             [1]
    },
    { 
      "id":               2,
      "seats":             [2]
    },
    { 
      "id":               3,
      "seats":             [3]
    },
    { 
      "id":               4,
      "seats":             [4]
    }
  ]
}

I’m having trouble getting the content out. Here’s my router.js:

App.Router.map( function() {
    this.resource('tournament', { path: "/" });
});

App.TournamentRoute = Ember.Route.extend({
    model: function() {
        return new Ember.RSVP.Promise( function (resolve, reject) {
        [..we just get the data return the json object above to setupController...]
        });
    },

    setupController: function (controller, model) {
        controller.set('model', model);
        [i do a little data computation here prior to the renderTemplate function]
    },

    renderTemplate: function () {
        var controller = this.controllerFor('tournament');
        this.render('tournament');
    }
});

My tournament.hbs template looks like this:

    <h1>{{tournament.title}}</h1>
    {{#each round in rounds}} Round id: {{round.id}} <br/>
        {{#each matchup in round.matchups}} matchup id: {{matchup.id}}
            <div class="matchup">
                {{#each seat in matchup.seats}}
                    <div class="entry">
                        {{seat.entry.id}}
                    </div>
                {{/each}}
            </div>
        {{/each}}
    {{/each}}

And I’m getting the following on screen:

March Madness!!!
Round id: 1 
matchup id:
matchup id:
Round id: 2 
matchup id:

So, a little bit of it is working. I’ve done some work in the console and at the matchup level, the matchup object is actually the values “1” and “2”, not matchups[0] and matchups1, as expected, which is why there is no “id” attribute next to the matchup levels. I’m not sure how much “magic” there is in Ember data by using conventions, and can’t find any examples that use this level of hierarchy. Thanks

My Models:

App.Tournament = DS.Model.extend({
    title: DS.attr('string'),
    active_round_index: DS.attr('number'),
    rounds: DS.hasMany('App.Round')
});

App.Round = DS.Model.extend({
    tournament: DS.belongsTo('App.Tournament'),
    matchups: DS.hasMany('App.Matchup')
});

App.Matchup = DS.Model.extend({
    round: DS.belongsTo('App.Round'),
    seats: DS.hasMany('App.Seat')
});

App.Seat = DS.Model.extend({
    matchup: DS.belongsTo('App.Matchup'),
    entries: DS.hasMany('App.Entry')
});

App.Entry = DS.Model.extend({
    title: DS.attr('string'),
    seats: DS.hasMany('App.Seat')
});

Also - I’m loadin my json without using the RESTAdapter… I’m doing it with the promises as defined in the docs here. My situation is unique in that I am only loading data once, and then using sockets for updates. So sideloading my data is particularly attractive…


#2

So, as it turns out, looks like the RESTAdapter is what does all the magic. I simply extended that and can now use my multi-level relationships.