Ember can't find model when URL is keyed in directly - ember.js

I'm using Ember 1.4 with EmberData beta 7. My application has the routes and models shown below:
App.Router.map(function () {
this.resource('strats', {path: "/"}, function() {
this.route('strat', {path: "/strat/:strat_id"});
});
});
App.StratsStratRoute = Ember.Route.extend({
model: function(params) {
return this.store.find(params.strat_id);
}
});
var attr = DS.attr;
var belongsTo = DS.belongsTo;
var hasMany = DS.hasMany;
App.StratLeg = DS.Model.extend({
legName: attr(),
quantity: attr(),
strat: belongsTo('strat')
});
App.Strat = DS.Model.extend({
stratName: attr(),
stratLegs: hasMany('stratLeg', {async:true})
});
I can transition into the strats.strat route via link-to fine. So for example, if I transition into the strats.strat route via link-to for id="dd-put", URL displays
http://localhost:8000/em.yaws#/strat/dd-put
and everything works. But now if I hit the refresh button, or type in that same URL after first transitioning to a different route, then I get this error message on the browser console and nothing displays:
Error while loading route: Error: No model was found for 'dd-put'
at new Error (native)
at Error.Ember.Error (http://localhost:8000/js/scripts/ember-1.4.0.js:844:19)
at Ember.Object.extend.modelFor (http://localhost:8000/js/scripts/ember-data-beta7.js:9762:33)
at Ember.Object.extend.findAll (http://localhost:8000/js/scripts/ember-data-beta7.js:9364:21)
at Ember.Object.extend.find (http://localhost:8000/js/scripts/ember-data-beta7.js:9046:23)
at App.StratsStratRoute.Ember.Route.extend.model (http://localhost:8000/js/app/ed.js:47:27)
at superWrapper [as model] (http://localhost:8000/js/scripts/ember-1.4.0.js:1239:16)
at Ember.Route.Ember.Object.extend.deserialize (http://localhost:8000/js/scripts/ember-1.4.0.js:35901:19)
at http://localhost:8000/js/scripts/ember-1.4.0.js:32521:57
at http://localhost:8000/js/scripts/ember-1.4.0.js:33000:19
Anyone know what's causing this?

Related

Error while processing route error in ember.js with ember-data

I'm trying to create an app using ember.js and ember-data, using the following versions:
DEBUG: Ember : 1.7.0
DEBUG: Ember Data : 1.0.0-beta.9
DEBUG: Handlebars : 1.2.1
DEBUG: jQuery : 2.1.0
I'm using the RESTAdapter to connect to an api I wrote using node.js.
As soon as I load the app I keep getting the following error:
Error while processing route: students undefined is not a function TypeError: undefined is not a function
at http://localhost:9000/scripts/vendor/ember-data.js:12006:34
at tryCatch (http://localhost:9000/scripts/vendor/ember.js:45818:16)
at invokeCallback (http://localhost:9000/scripts/vendor/ember.js:45830:17)
at publish (http://localhost:9000/scripts/vendor/ember.js:45801:11)
at http://localhost:9000/scripts/vendor/ember.js:29069:9
at DeferredActionQueues.invoke (http://localhost:9000/scripts/vendor/ember.js:634:18)
at Object.DeferredActionQueues.flush (http://localhost:9000/scripts/vendor/ember.js:684:15)
at Object.Backburner.end (http://localhost:9000/scripts/vendor/ember.js:147:27)
at Object.Backburner.run (http://localhost:9000/scripts/vendor/ember.js:202:20)
at apply (http://localhost:9000/scripts/vendor/ember.js:18382:27)
Here's the code I'm using (loaded in the same order I pasted it):
app.js
var App = window.App = Ember.Application.create({
LOG_ACTIVE_GENERATION: true,
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: false,
LOG_VIEW_LOOKUPS: true
});
store.js
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:3000',
serializer: DS.RESTSerializer.extend({
primaryKey: function(type) {
return '_id';
},
serializeId: function(id) {
return id.toString();
}
})
});
models/student.js
App.Student = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
nationality: DS.attr('string'),
createdAt: DS.attr('date')
});
routes/app_route.js
App.StudentsRoute = Ember.Route.extend({
model: function() {
return this.store.find('student');
}
});
router.js
App.Router.map(function () {
this.resource('students', {path: '/'});
});
And the following is the response of the API:
{
students: [
{
nationality: "Lorem",
lastName: "Doe",
firstName: "John",
_id: "53f87200f3750319b4791235",
createdAt: "2014-08-23T10:50:40.661Z"
},
{
nationality: "Lorem",
lastName: "Doe",
firstName: "John",
_id: "53f87299f3750319b4791234",
createdAt: "2014-08-23T10:50:40.661Z"
}
]
}
It looks like the store is not loading the data from the API, but the JSON data format looks fine. Any idea of what could be wrong?
Thanks!
So after searching more on Stack Overflow, I've figured out that the serializer has now to be in a separate class than the RESTAdapter, so the working code is the following:
store.js
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:3000'
});
App.ApplicationSerializer = DS.RESTSerializer.extend({
primaryKey: '_id',
serializeId: function(id) {
return id.toString();
}
});
Here's an updated answer for people using ember-cli.
ember g adapter application #=> creates app/adapters/application.js
ember g serializer application #=> creates app/serializers/application.js
In app/adapters/application.js:
import DS from 'ember-data';
export default DS.RestAdapter.extend({
host: 'http://localhost:3000'
});
In app/serializers/application.js:
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
primaryKey: '_id',
serializeId: function(id) {
return id.toString();
}
});
I was getting this error, and it had nothing to do with any of the usual suspects.
In coffeescript, I had started defining a model.
App.Cost = DS.Model.extend
amount: DS.attr 'number'
active: DS.attr 'boolean'
To create a second model, I c/p my first model in and deleted the attributes:
App.Cost = DS.Model.extend
The went back and tried to run a seemingly unrelated model
localhost:3000/products
Which resulted in the error
Error while processing route: products.index
Simply making sure my model was named correctly solved the error:
App.Cost = DS.Model.extend(...)
App.Price = DS.Model.extend(...) <- instead of repeating the Cost model
This was re-produceable, so I thought it might be helpful to others.

No resource 'posts' Ember App

I'm moving over from Backbone to Ember, and to start to get the swing of things I'm trying to make a Blog App.
I get the error --
Uncaught Error: Assertion Failed: The attempt to link-to route 'posts' failed. The router did not find 'posts' in its possible routes: 'loading', 'error', 'index', 'application'
This is what I have so far --
Blog.Router.map = function() {
this.resource('posts');
}
Blog.PostsRoute = Ember.Route.extend({
model: function() {
this.get('store').findAll('post')
}
})
Blog.Post = DS.Model.extend({
name: DS.attr('string')
});
map is a function, not a property you set.
Blog.Router.map( function() {
this.resource('posts');
});

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.

Nesting resources error

I've followed this example http://emberjs.com/guides/controllers/dependencies-between-controllers/ to implement a nested resource for my app but continue to receive route and type errors.
I've created my route as follows:
App.Router.map(function () {
this.resource('logs', {path: '/'}, function(){
this.resource('log', {path:'/logs/:log_id'}, function(){
this.resource('triggers');
});
});
});
My controller:
App.TriggersController = Ember.ArrayController.extend({
needs:"log"
});
Model:
App.Log = DS.Model.extend({
name: DS.attr('string'),
type: DS.attr('string'),
messages: DS.attr('string'),
triggers: DS.hasMany(App.Trigger, {async:true})
});
Child Model:
App.Trigger = DS.Model.extend({
name: DS.attr('string'),
pattern: DS.attr('string'),
isEnabled: DS.attr('boolean'),
colour: DS.attr('string'),
highlightText: DS.attr('boolean'),
invertContrast: DS.attr('boolean')
});
JSFiddle link : http://jsfiddle.net/WZp9T/11/
Click on one of the links and you should see the error in console.
("Error while loading route: TypeError {}" and "Uncaught TypeError: Cannot read property 'typeKey' of undefined" as well as a deprecation warning)
Basically, what I'm trying to achieve is:
Logs -> Log -> Log Triggers -> Trigger
Each context should remain on screen, where exactly am I going wrong?
EDIT: It seems to be a problem with this:
App.LogIndexRoute = Ember.Route.extend({
model: function (params) {
return this.store.find(params.log_id);
}
});
If I remove that piece of code I no longer receive my errors.
You need to tell the store which kind of object you want to look up. Right now you're just passing it an ID. This is probably what you're looking for:
App.LogIndexRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('log', params.log_id);
}
});

Serialize is reached before server response is complete

In my ember app, I have a router with nested resources, like so:
App.Router.map(function () {
this.resource('explore', function() {
this.resource('building', { path: 'building/:slug' });
this.resource('country', { path: ':slug' }, function() {
this.resource('state', {path: ':slug' });
});
});
});
App.CountryRoute = Ember.Route.extend(App.SlugRouter, {
setupController: function(controller, country) {
controller.set('title', 'country detail');
controller.set('model', country);
}
});
App.SlugRouter = Ember.Mixin.create({
serialize: function(model, params) {
var name, object;
object = {};
name = params[0];
object[name] = model.get('slug');
return object;
}
});
App.Building = DS.Model.extend({
country: DS.belongsTo('App.Country'),
name: DS.attr('string'),
slug: DS.attr('string')
});
App.Country = DS.Model.extend({
name: DS.attr('string'),
slug: DS.attr('string'),
buildings: DS.hasMany('App.Building'),
states: DS.hasMany('App.State')
});
Loading the explore route shows a list of buildings received from the server (a django-rest-framework app), each building has a relationship to a country with a belongsTo attribute.
In the explore.index route, I display the list of the buildings, with links to the country route for each building, using {{linkTo this.country}}. The href, however, is loaded as #/explore/undefined, instead of #/explore/<country-name>.
The part that is confusing me is that this only happens the first time that I load the list. If I go to another route, then come back to #/explore, the links render correctly.
In the debugger, putting a breakpoint in the serialize method, I see that the first time that I load the page, the model object is empty (_data.attributes is an empty object). Going to the network tab in the debugger, I see that the a request has been made to the server to get the country data, but the response has not been received yet:
The response is eventually received, since {{this.country.name}} renders correctly, but after it's too late.
Thanks in advance for any responses/tips.
I am using:
Ember: 1.0.0-rc.5,
Handlebars: 1.0.0-rc.4,
jQuery: 1.8.3,
ember-data: 0.13,
ember-data-django-rest-adapter: 0.13
Firstly you are mixing in App.SlugRouter before it's definition. You should be seeing an error like Assertion failed: Expected hash or Mixin instance, got [object Undefined] in the console.
After that you need to load the model for a country by the slug. I don't see this in your Route either. You need something like this in CountryRoute depending on your persistence library.
model: function(params) {
return App.Country.find({slug: params.slug});
}
I suspect the part that is working right now is because your index route is loading the model and passing it in to setupController with the linkTo. Direct loading of the nested page requires configuring that route's model hook.