Ember-Data: How do "mappings" work
Asked Answered
A

3

11

I'm currently trying to put something together with ember + emberdata + router + asp.net web api. Most of it seem to work, however I stuck in an error message I get when ember-data tries to findAll through the adapter for my models.

In my backend I have a model like this (C#):

public class Genre {
    [Key]
    public int Id { get; set; }
    [Required]
    [StringLength(50, MinimumLength=3)]
    public string Name { get; set; }
}

Which in my app I represent it like this using ember-data:

App.Genre = DS.Model.extend({
    id: DS.attr("number"),
    name: DS.attr("string")
}).reopenClass({
    url: 'api/genre'
});

I have also a Store defined in my App using the RESTAdapter like so:

App.store = DS.Store.create({
    revision: 4,
    adapter: DS.RESTAdapter.create({
        bulkCommit: false
    })
});

And the store is used in my controller as below:

App.GenreController = Ember.ArrayController.extend({
    content: App.store.findAll(App.Genre),
    selectedGenre: null
});

The router is defined as

App.router = Em.Router.create({
    enableLogging: true,
    location: 'hash',
    root: Ember.Route.extend({
        //...

        genre: Em.Route.extend({
            route: '/genre',
            index: Ember.Route.extend({
                connectOutlets: function (router, context) {
                    router.get('applicationController').connectOutlet('genre');
                }
            })
        }),

        //...
    })
})

When I run my application, I get the following message for every object that has this same structure:

Uncaught Error: assertion failed: Your server returned a hash with the key 0 but you have no mappings

For reference, here's the json the service is returning:

[
  {
    "id": 1,
    "name": "Action"
  },
  {
    "id": 2,
    "name": "Drama"
  },
  {
    "id": 3,
    "name": "Comedy"
  },
  {
    "id": 4,
    "name": "Romance"
  }
]

I cannot tell exactly what the problem is and since the assertion is mentioning that I need mapping, I'd like to know:

  1. What this mapping is and how to use it.
  2. Since the returned json is an array, should I be using a different type of controller in my app ,or is there anything I should know about when working with this type of json in ember-data? or should I change the JsonFormatter options in the server?

Any help is welcome.

I can definitely add more information if you feel this isn't enough to understand the problem.

EDIT: I've changed a few things in my backend and now my findAll() equivalent action in the server serializes the the output as the following json:

{
  "genres": [
      { "id": 1, "name": "Action" },
      { "id": 2, "name": "Drama" },
      { "id": 3, "name": "Comedy" },
      { "id": 4, "name": "Romance" }
   ]
}

But I still can't get it to populate my models in the client and my error message has changed to this:

Uncaught Error: assertion failed: Your server returned a hash with the key genres but you have no mappings

Not sure what else I might be doing wrong.

The method that throws this exception is sideload and checks for the mappings like this:

sideload: function (store, type, json, root) {
        var sideloadedType, mappings, loaded = {};

        loaded[root] = true;

        for (var prop in json) {
            if (!json.hasOwnProperty(prop)) { continue; }
            if (prop === root) { continue; }

            sideloadedType = type.typeForAssociation(prop);

            if (!sideloadedType) {
                mappings = get(this, 'mappings');
                Ember.assert("Your server returned a hash with the key " + prop + " but you have no mappings", !!mappings);
//...

This call sideloadedType = type.typeForAssociation(prop); returns undefined and then I get the error message. The method typeForAssociation() checks for the for 'associationsByName' key which returns an empty Ember.Map.

Still no solution for this at the moment.

By the way...

My action is now like this:

    // GET api/genres
    public object GetGenres() {
        return new { genres = context.Genres.AsQueryable() };
    }

    // GET api/genres
    //[Queryable]
    //public IQueryable<Genre> GetGenres()
    //{
    //    return context.Genres.AsQueryable();
    //}

I had to remove the original implementation which gets serialized by json.NET as I could not find config options to produce a json output as Ember-Data expects ( as in {resource_name : [json, json,...]}). Side effect of this is that I've lost built-in OData support, but I'd like to keep it. Does anyone know how could I configure it to produce different json for a collection?

Advocaat answered 29/8, 2012 at 16:53 Comment(0)
G
12

The mapping can be defined in the DS.RESTAdapter. I think you could try to define something like this:

App.Store = DS.Store.extend({
  adapter: DS.RESTAdapter.create({
    bulkCommit: true,
    mappings: {
      genres: App.Genre
    },
    // you can also define plurals, if there is a unregular plural
    // usually, RESTAdapter simply add a 's' for plurals.
    // for example at work we have to define something like this
    plurals: {
      business_process: 'business_processes' 
      //else it tries to fetch business_processs
    }
  }),
  revision: 4
});

Hope this resolves your problem.

Update:

At this time, this is not well documented, I don't remember if we found it by ourself reading the code, or perhaps Tom Dale pointed on it.
Anyway, here is the point for plurals For the mappings, I think we were driven by the same error as you, and either we tried, either Tom teached us about this.

Geognosy answered 30/8, 2012 at 22:9 Comment(2)
Both answers helped, I guess I really didn't know where to set the mappings. Now I'm gonna finally start working with the views and templates. Thanks SylvainAdvocaat
Last thing on this, I couldn't find any specifics on mappings. Could you point out where I could have found it? If it's only in source code? It could/should be available in the readme tho.Advocaat
S
8

The RESTAdapter expects the returned JSON to be of the form:

{
  "genres": [{
    "id": 1,
    "name": "action"
  },{
    "id": 2,
    "name": "Drama"
  }]
}

The tests are a good source of documentation, see https://github.com/emberjs/data/blob/master/packages/ember-data/tests/unit/rest_adapter_test.js#L315-329

Selfeffacement answered 29/8, 2012 at 18:54 Comment(2)
I managed to make my service to produce json on the same format but now I get the message "Uncaught Error: assertion failed: Your server returned a hash with the key genres but you have no mappings". I managed to load with a different set of controllers/models with ember 0.9.1 and no ember-dataAdvocaat
Well, unfortunately it's not the json format, it's something else now as I'm returning the format indicated above and now I get the same message for another property and no longer for the index.Advocaat
A
3

I'm using Ember Data rev. 11 and it seems that the plurals config in DS.RESTAdapter.create never works. I looked into the codes and found a solution as following:

App.Adapter = DS.RESTAdapter.extend({
  bulkCommit: false
})

App.Adapter.configure('plurals', {
  series: 'series'
})
Adventuress answered 28/3, 2013 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.