简体   繁体   中英

Emberjs models with relations throws an error: “Cannot set property 'store' of undefined”

I'm trying out ember at my work to see if we should use it for our future applications I am doing a simple test application and I wanted to try out the relations between the models. This is the code I have that defines the models:

var App = Ember.Application.create();

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

App.Store = DS.Store.extend();

App.Conf = DS.Model.extend({
    module : DS.attr(),
    reports: DS.hasMany('report'),
    isClean: function() {
        return !this.get('reports').isAny('isClean', false);
    }.property('reports.@each')
});


App.Report = DS.Model.extend({
    country: DS.attr(),
    google_account_id: DS.attr(),
    web_property_id: DS.attr(),
    custom_source_uid: DS.attr(),
    isClean: function() {
        return (
                this.get('country') != '' &&
                this.get('google_account_id') != '' &&
                this.get('web_property_id') != '' &&
                this.get('custom_source_uid') != ''
                );
    }.property('country', 'google_account_id', 'web_property_id', 'custom_source_uid')
});

App.ApplicationAdapter = DS.RESTAdapter.extend({
    host: 'http://playground.loc/battle_of_frameworks/json.php'
});

…and here is the JSON that is being loaded:

The error I get is:

Error while loading route: TypeError: Cannot set property 'store' of undefined

I Googled the problem and it's usually something about naming your models in plural (ie: App.Reports) which I'm not doing. So I am not sure what the problem is here. Can anyone give any insights?

There are several problems in your code.

Your server doesn't provide the payload expected by Ember Data. I would recommend reading this document about customizing your serializer if you can't generate the proper json payload with your backend.

Ember.js is all about convention over configuration. Right now, you are not following those conventions:

  • attributes are camelcased

     App.Report = DS.Model.extend({ googleAccountId: DS.attr() //instead of google_account_id }); 
  • you don't need to create the index route, it comes for free in Ember . So your router should simply look like:

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

  • Are you sure that your backend expects the Config to be served from /config/:config_id and not /configs/:config_id ?

  • You declare a config resource. The convention is to have a App.Config model and not App.Conf

In order to clean your code, you can also take advantage of computed properties to DRY your code:

App.Report = DS.Model.extend({
  country: DS.attr(),
  googleAccountId: DS.attr(),
  webPropertyId: DS.attr(),
  customSourceUid: DS.attr(),
  isClean: Ember.computed.and('country', 'googleAccountId', 'webPropertyId', 'customSourceUid')
});

You also need to pay attention when defining a computed property based on an array. The isClean of Config uses isClean of Report but your computed property observes only the elements of your Report association. The correct way of writing it is:

App.Config = DS.Model.extend({
  module : DS.attr(),
  reports: DS.hasMany('report'),
  isClean: function() {
    return !this.get('reports').isAny('isClean', false);
  }.property('reports.@each.isClean')  //make sure to invalidate your computed property when `isClean` changes
});

I hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM