I’m facing this error since yesterday, Error: Assertion Failed: 'todo' was saved to the server, but the response does not have an id and your record does not either.
I know it should come from app/serializers/todo.js or my app/routes/application.jsbut after looking into severals forum, I have to ask the question to expert emberJs dev, as i’m a newbie :smiley:
Here’s my app/serializers/todo.js:
import DS from 'ember-data';
export default DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = this._super.apply(this, arguments); // Get default serialization
json.id = record.id; // tack on the id
return json;
}
});
And my app/routes/application.js
import Route from '#ember/routing/route';
export default Route.extend({
model(){
return this.store.findAll('todo');
},
actions: {
createtodo: function() {
var titleInput = this.get("newTitle")
var todo = this.store.createRecord('todo', {
title: titleInput,
isCompleted: false
});
this.set('newTitle', '');
todo.save();
}
}
});
The way the createtodo action is triggered app/templates/application.hbs:
{{input type="text" id="new-todo" value=newTitle}}
<button {{action "createtodo"}}>Save</button>
So my objec is created but not save. When i’m looking into my ember Inspector, I see that each object I create have an ID but the title field is null or "".
This is a todoApp with an Rails-API as back and Ember as front.
Anyone see what’s wrong here ?
Your serializer is the problem. If you're using a somewhat standard api setup, you shouldn't really need the serializer at all. I'd delete that first.
What's likely happening is that your API isn't setup to recieve JSON-API documents, which are structured like:
{
id: <id>,
type: <type>,
attributes: {
name: <string>,
created: <date>,
complete: <boolean>
}
}
So you should either install a json-api gem on the backend or switch the adapter to use the DS.RestSerializer, which has a totally flat data structure.
I've got a model called "Membership" that has a string attribute "inviteToken" which I would like to use as my primary key.
I've created the following serializer, but cannot get it to pick up the primary key from the JSON.
app/serializers/membership.js:
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
primaryKey: 'invite-token' // also tried 'inviteToken'
});
The specific error I'm getting is:
Error while processing route: invitations.show Assertion Failed: You
must include an 'id' for membership in an object passed to 'push'
Error: Assertion Failed: You must include an 'id' for membership in an
object passed to 'push'
Which happens when I try to get a record by its ID in the route:
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.find('membership', params.token);
}
});
API Response:
{
"jsonapi":{
"version":"1.0"
},
"data":{
"type":"membership",
"id":"30",
"attributes":{
"invite-token":"5bGo7IhZh93E4SB07VWauw"
}
}
}
The strange thing is that if I use "type" as the primary key, I see "membership" as the id in the ember inspector. It's as if ember data doesn't know how to use something from the "attributes". I'm using ember data 2.4.0.
Update
I can hack this to work in my serializer by doing this:
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
normalize: function(type, hash) {
const json = this._super(type, hash);
json.data.id = json.data.attributes.inviteToken;
return json;
}
});
The serializer expects the value of primaryKey to refer to a top level element in the json. This is why "type" and "id" works. It currently does not support nested properties (for example primaryKey: "attributes.invite-token")
However there are two good workarounds:
The first is overriding the extractId method. The default implementation is quite simple. In your case you could do something like:
extractId(modelClass, resourceHash) {
var id = resourceHash['attributes']['invite-key';
return coerceId(id);
},
The second way is the method you discovered, a more brute force approach, and that is to assign the id manually in the normalize function.
I have to send the requests to "http:example.com/api/galleries/gallery_id/photos.The gallery_id is varying and I am getting it from params.id. Now the problem I am facing is that the response from a server is an array of objects.So what should I use?By That, I meant (findAll or findRecord).When I use FindRecord it make the correct call But is not able to serialize the data.When I use findAll it calls the wrong API.
My Serializer
import DS from 'ember-data';
export default DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin,{
isNewSerializerAPI: true,
primaryKey:'pk',
normalize: function(typeClass, hash) {
console.log(hash)
var fields = Ember.get(typeClass, 'fields');
fields.forEach(function(field) {
var payloadField = Ember.String.underscore(field);
if (field === payloadField) { return; }
hash[field] = hash[payloadField];
delete hash[payloadField];
});
return this._super.apply(this, arguments);
}
});
This is the error I am getting is
Assertion Failed: You must include an 'id' for gallery in an object passed to 'push'
I am building an emberjs app and I want to call my REST API for results. I have this code:
App.Post = DS.Model.extend();
App.PostAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1',
host: 'http://myapp.com'
});
And in the controller I have this
post: this.store.find('post')
The problem is that it always calls with "s" added in the end, for example - http://myapp.com/api/v1/posts
How do I remove the plural form from these calls?
You need to override the pathForType method in your adapter.
App.PostAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
var camelized = Ember.String.camelize(type);
return Ember.String.singularize(camelized);
}
});
var inflector = new Ember.Inflector();
inflector.singularize('posts');
Ember put 's' automatically. You need to force it to use singular. Above code tells Ember to request to myapp.com/post when you call this.store.find('post'); otherwise default behaviour will try to send request to myapp.com/posts
I had same issue once upon a time. I could not even found a way to set this behaviour globally. I have repeated this code ( inflector.singularize('posts'); ) for every store.
I need to get the current route name in my ember application; I tried this:
Ember App.Router.router.currentState undefined
but it doesn't work for me (there is probablig something i'm missimg...) I use Ember rc6 and I have a multilingual app; in the applicationRoute I detect the browser's language and I redirect to the correct page with:
this.transitionTo(userLang);
but I would like this to be executed only when user are on the home page, so something like this:
if (currentRoute == 'home'){
this.transitionTo(userLang)
}
NOTE: as of Ember 3.16, the original answer is not only recommended, but observers are strongly discouraged.
To get the current route name, you can utilize the Router Service: https://api.emberjs.com/ember/3.18/classes/RouterService/properties/currentRouteName?anchor=currentRouteName
export default class MyComponent extends Component {
#service router;
get activeRoute() {
return this.router.currentRouteName;
}
}
Original answer below
You could observe the application's currentPath and set it to the current route accordingly when it changes:
App = Ember.Application.create({
currentPath: '',
});
App.ApplicationController = Ember.Controller.extend({
updateCurrentPath: function() {
App.set('currentPath', this.get('currentPath'));
}.observes('currentPath')
}),
This way you have access to the currentPath when ever you want with App.get('currentPath');
E.g.
if (App.get('currentPath') == 'home'){
this.transitionTo(userLang);
}
Hope it helps.
This worked for me on 1.3.0-beta (and a quick glance at the source for 1.1.2 suggests it would work there too):
App.__container__.lookup('router:main').location.lastSetURL
Note that the documentation states:
At present, it relies on a hashchange event existing in the browser.
However, I believe it's strongly suggested that App.__container__ not be used in production code. A more acceptable alternative would be to use App.Router.router.currentHandlerInfos, which provides information on the current Ember route.
Yet another option is currentRouteName on the ApplicationController. You can add needs: ['application'] to your controller, then access the route name with controllers.application.currentRouteName. This will return something like posts.index.
With the shift to components, it is harder to get route name. The best way is to add an initializer such as
ember g initializer router
(from command line), and
export function initialize(application) {
application.inject('route', 'router', 'router:main');
application.inject('component', 'router', 'router:main');
}
export default {
name: 'router',
initialize
};
in a initializers/router.js. You can also inject into controller if you need to. Then just do simply
this.get('router.currentRouteName');
in JS, or
{{router.currentRouteName}}
in template.
This is the only way I have found to get it reliably, and observable in Ember 2.4
If you want to get current route in your component or controller you can inject routing service (routing: Ember.inject.service('-routing'))
(for more) and use:
this.get('routing.currentRouteName') or this.get('routing.currentPath')
Example with component and computed property:
import Ember from 'ember';
export default Ember.Component.extend({
routing: Ember.inject.service('-routing'),
checkMyRouteName: Ember.computed('routing.currentRouteName', function() {
return this.get('routing.currentRouteName');
})
})
Example with controller and computed property:
import Ember from 'ember';
export default Ember.Controller.extend({
routing: Ember.inject.service('-routing'),
checkMyRouteName: Ember.computed('routing.currentRouteName', function() {
return this.get('routing.currentRouteName');
})
})
Current route in your route you just need this.routeName
Example with route:
import Ember from 'ember';
export default Ember.Route.extend({
checkMyRouteName() {
return this.routeName;
}
})
Just as an update, in Ember 1.8.1, we can get the routeName inside an Ember.Route object by doing this.routeName.
Currently as of Ember 1.7.0 you can get the current route from within a route by calling this.routeName.
The Ember namespace API now has a getOwner method, which is very useful for looking up the currentRouteName, or, other route properties.
const owner = Ember.getOwner(this);
const currentRoute = owner.lookup('router:main').currentRouteName;
const routeInfo = owner.lookup(`route:${currentRoute}`).get('info');
// etc.
I've created an Ember Twiddle example to demonstrate. Use the text input above the "Output" pane to hit other routes like /blue, /green, or /red.
Ember has a RouterService since 2.15. It provides the name of the current route as currentRouteName property. A polyfill exists for Ember 2.4 - 2.14 if you are still on such an old version.
import Component from '#ember/component';
export default Component.extend({
router: service(),
isHomeRoute: computed('router.currentRouteName', function() {
return this.router.currentRouteName === 'home';
}),
});
All other solutions mentioned here are relying on private API that might already be deprecated / removed. Using RouterService is working at least up the current version, which is 3.12 at the time of writing this.
Please note that the "home" is not /. The root URL is called "index".
I had the same problem for a while. then i started exploring router. It always have a state object which can be obtained from any route using
var route = this;
var handlerInfos = route.get("router.router.state.handlerInfos");
var currRouteHandlerInfo = handlerInfos[handlerInfos.length-1];
var currRouteName = currRouteHandlerInfo.name; //"home"
that's it. Now you have the current route name!
if you want the current route params,
var routerParams = this.get("router.router.state.params");
var currRouteParams = routerParams[currRouteName]; //{ homeId : "1" }
You can simple parse the current URL. This way you can use your full url for example:
http://127.0.0.1:8000/index.html/#/home
and extract from this string the suffix:
/home
which is the current route name.
A simple JS function (that works regardless to your Ember version) will be:
function getCurrentRoute()
{
var currentRoute;
var currentUrl = window.location.href; // 'http://127.0.0.1:8000/index.html/#/home'
var indexOfHash = currentUrl.indexOf('#');
if ((indexOfHash == -1) ||
(indexOfHash == currentUrl.length - 1))
{
currentRoute = '/';
}
else
{
currentRoute = currentUrl.slice(indexOfHash + 1); // '/home'
}
return currentRoute;
}
Example of use:
if (getCurrentRoute() == '/home')
{
// ...
}