I have a Post model with the following fields:
BlogApp.Post = DS.Model.extend({
author: DS.attr('string'),
title: DS.attr('string'),
preamble: DS.attr('string'),
content: DS.attr('string'),
created: DS.attr('date'),
comments: DS.hasMany('BlogApp.Comment'),
lastUpdate: DS.attr('date')
});
After rendering, instead of the Post.content, the result is like:
<BlogApp.Post:ember272:1>
Other fields rendering are OK. I'm very new to Ember, but I guess content is conflicting with some internal property.
Perhaps all reserved attribute names should be prefixed by an underscore in order to avoid conflicts with user created properties.
content is not conflicting with ember-data model but with Ember.Controller. I would suggest to use ember-data mapping api to name your attribute body for example but still use content on the api.
App.Post = DS.Model.extend({
body: DS.attr('string')
});
App.Adapter.map('App.Post', {
body: {key: 'content'}
});
Basically any method/property on the DS.Model prototype or Ember.Container prototype is a reserved name. We should probably list them at some point. I think the mapping api is ok to handle collisions.
Thanks, nice to know there is a workaround.
I still think that naming the property '_content' instead of just 'content' would reduce the risk of a name clash.
@scardine it would not solve the problem. There is tons of other "reserved" properties model, transaction, isNew, isDeleted, store, errors etc... All of these would make sens as model property. But they are all part of public api. This is the price to pay for using an ORM.
The "_something" convention seems to work very well for Python, and I would like to see more of it in JS libraries.
But ok, I agree, like said by Machiavelli, "he who has not first laid his foundations may be able with great ability to lay them afterwards, but they will be laid with trouble to the architect and danger to the building". Perhaps it is to late to change the foundations (adopt _model, _transaction, _isNew, _isDeleted, _store, _errors). I had to try anyway...
@scardine many js libraries use "_" for private methods. So do Ember. But the api we are taking about is public. You saying that in python the convention is to make all the library methods pseudo privates?
Any concept of public/private in languages like JS or Python is a matter of convention. I'm not saying that in python the convention is to make all the library methods pseudo privates, but it is common practice to rename attributes when there is potential to shadow a built-in type, module name or reserved word.
In ORM-like APIs, when you are magically mapping field names from external databases, it makes sense to mitigate the potential for conflicts, either using a naming convention or reducing the surface of contact by corralling either the API methods or the magically mapped attributes in a specific namespace.
@tchak: BTW, Angular.js got it right (don't want to be disrespectful mentioning a competing framework, I just like some of their design decisions and think Ember could borrow some ideas). After one week banging my head with Ember, I tried Angular - my impressions so far:
Ideas that Angular could borrow from Ember:
Ideas that Ember could borrow:
$, very easy to avoid clashes with user code. Closing since this ticket is inactive and not something we're likely to change.
@scardine, thanks for the feedback.
Like @scardine I ran into this issue today. I'd suggest to throw an error message if an user tries to use "reserved words" as model attributes.
Same here. And I do agree if you are not changing it. Please both mention it in the doc and log a warning if a model used reserved keywords.
:+1: for logging a warning. Came across this in Component as well where 'trigger' and 'container' are reserved but both are used in Bootstraps popovers.
An alternative approach could mangle the keys used for the data fields when setting and retrieving them. So if my data has the key attributes in it, internally, Ember could store that key as ~attributes. Then when I call model.get('attributes'), internally, Ember could look up the key as ~attributes. That way, data keys can't clash with public API, and this unfortunate namespace overloading would not be exposed to user code. Might something like this work well?
I personally believe the model's data should be stored on record.data and accessed there explicitly to prevent collisions with needed keywords.
@runspired we considered following json api and having .attributes and .relationships but feared the upgrade emo would be too much
At the very least:
Better would be a design that made collisions impossible, this includes approaches like:
model.data.foo)model.$errors (a la angular)model.errors is the ember builtin that shadows model attribute: model.$errors would get to the attribute; it's just an alias, so all model attributes could be accessed as model.$content, model.$store, model.$firstName, etc., as needed.This really should not have been closed. Just ran into an issue today where some attributes named data_* weren't showing up due to that being reserved. :/
Edit: ignore me, I was just being an idiot and didn't realize the way the JSONAPI serializer handles underscores
import DS from 'ember-data';
export default DS.Model.extend({
type: DS.attr('string'),
});
type itself is also reserved. Weird.
i.e. See source code
function deserializeRecordId(store, key, relationship, id) {
if (isNone(id)) {
return;
}
(0, _emberDataPrivateDebug.assert)('A ' + relationship.parentType + ' record was pushed into the store with the value of ' + key + ' being ' + _ember['default'].inspect(id) + ', but ' + key + ' is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.', !Array.isArray(id));
//TODO:Better asserts
return store._internalModelForId(id.type, id.id); // <-- id.type
}
my guess would be that id refers to a json api resource identifier and not the model attribute. the resource identifier consists of a type and id.
@ldong i have used 'type' as an attribute in my model as String , i didnt face any issue.
I believe reason is also a reserved word for ember data. Are these reserved words documented anywhere? I have personally spent a lot of time discovering these landmines. It would really improve the usability of ember data to have a list of these words documented somewhere.
When you conflict with one of these reserved words it is really brutal to try to debug.
We've found more reserved words that cause ember data to fail silently with no feedback:
reason
protected
trigger
This is an enormous stumbling block for developers. When you set up everything correctly (db, serializers on server, ember data models, router, route, template) and your attribute just doesn't show up on the page and there are no errors -- what are you supposed to think as a developer? "Somewhere along the line I probably fat-fingered something," right? So you bang your head against the wall going over and over and over your code only to eventually realize "oh I can't name my attribute this -- WHY DIDN'T ANYONE TELL ME??"
I'm sure there are more reserved words lurking out there for me to stumble on. Could there at least be a list somewhere?
/cc @wycats @tomdale because I know you guys care about developer ergonomics
@igorT Does your model-data branch will handle this ?
@bmac Maybe could we add those in the RESERVED_MODEL_PROPS array ?
Most helpful comment
At the very least:
Better would be a design that made collisions impossible, this includes approaches like:
model.data.foo)model.$errors(a la angular)model.errorsis the ember builtin that shadows model attribute:model.$errorswould get to the attribute; it's just an alias, so all model attributes could be accessed asmodel.$content,model.$store,model.$firstName, etc., as needed.