aledujke
aledujke

Reputation: 1135

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?

Upvotes: 1

Views: 921

Answers (1)

Cyril Fluck
Cyril Fluck

Reputation: 1581

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('[email protected]')  //make sure to invalidate your computed property when `isClean` changes
});

I hope this helps.

Upvotes: 1

Related Questions