pushObject is undefined on model Ember 1.13

Hello,

I’m having this error om my model : Uncaught TypeError: Cannot read property 'pushObject' of undefined

So I have two models with Relations like this :

var ApplicationPasswords = DS.Model.extend({
  userId: DS.belongsTo('user', {async: true}),
  passwordName: DS.attr('string'),
  username: DS.attr('string'),
  password: DS.attr('string'),
  system: DS.attr('boolean'),
});

and

var User = DS.Model.extend({
  firstname: DS.attr('string'),
  lastname: DS.attr('string'),
  login: DS.attr('string'),
  passwordGen: DS.attr('string'),
  groups: DS.hasMany('group', {async: true}),
  rights: DS.hasMany('right', {async: false}),
  serializedRights: DS.attr(),
  language: DS.attr('string'),
  source: DS.belongsTo('ldap', {async: true}),
  applicationPasswords: DS.hasMany('application-passwords', {async: true}),
  isInternal: Ember.computed.equal('source.id', '0'),

In the controller on the model user, I’m trying to insert a applicationPasswords like that :

createApplicationPasswords: function(partner) {
      const currentUser = this.currentUser;
      console.log(currentUser.model);
      console.log(currentUser.model.id);
      const newAp = this.store.createRecord('application-passwords', {
        userId: currentUser.model.id,
        passwordName: 'partner_id=' + partner.id,
        username: this.get('newUsername'),
        password: this.get('newPassword'),
        system: false,
      });
      newAp.save();
      currentUser.get('applicationPasswords ').pushObject(newAp);
      currentUser.save();
    },

but I’m having undefined on currentUser.get('applicationPasswords ').pushObject(newAp);

I don’t really know why, my model is declared, I have no route on applications-password model because I’m using in inside the controller of user model.

Ember 1.13

I noticed the code you posted has an extra space after applicationPasswords, that may or may not be a problem…

      currentUser.get('applicationPasswords ').pushObject(newAp);
                                           ^

I would try removing the whitespace, then setting a breakpoint on that line and checking what currentUser.get('applicationPasswords') is in the console.

@dknutsen

Hi, thank you for your response.

It was probably a formatting problem when I copied and pasted, so I still have the problem.

currentUser is how I get my current user here is the relevant output :

Class {__ember1617783186782: null, __nextSuper: undefined, __ember_meta__: {…}}
model: Class
adapterError: null
container: Container {_registry: Registry, cache: {…}, factoryCache: {…}, validationCache: {…}, __1617783186877_owner: FakeOwner}
currentState: {setup: ƒ, didSetProperty: ƒ, pushedData: ƒ, becomeDirty: ƒ, willCommit: ƒ, …}
id: "1"
isError: false
store: Class {_backburner: Backburner, typeMaps: {…}, recordArrayManager: Class, _pendingSave: Array(0), _instanceCache: ember$data$lib$system$store$container$instance$cache$$ContainerInstanceCache, …}
_internalModel: InternalModel {id: "1", store: Class, container: Container, _data: {…}, type: ƒ, …}
language: (...)
login: (...)

Ah that makes sense.

What I meant RE: inspecting was the contents of the relationship on currentUser. Based on the error it sounds like currentUser.get('applicationPasswords') will be undefined, but in Ember Data 1.13 it should be a ManyArray instantiated lazily when it is first fetched, which would give you pushObject.

Then again I totally forget how this worked in Ember 1.13 (that was a long time ago :grin:). I’d also try looking into the _internalModel and model classes and looking at the relationships to make sure they’re set up correctly (your model code looks fine).

Your comments made me realize that in my store do not have any applicationPasswords set. I mean that this ManyArray is empty. But the error throws undefined as it is not instantiated or something…

In fact, I search into _internalModel and into the field relationships as you said. I can see that my applicationPasswords is not initialized :

initializedRelationships: ember$data$lib$system$empty$object$$EmptyObject
groups: ember$data$lib$system$relationships$state$has$many$$ManyRelationship {members: ember$data$lib$system$ordered$set$$OrderedSet, canonicalMembers: ember$data$lib$system$ordered$set$$OrderedSet, store: Class, key: "groups", inverseKey: "users", …}
rights: ember$data$lib$system$relationships$state$has$many$$ManyRelationship {members: ember$data$lib$system$ordered$set$$OrderedSet, canonicalMembers: ember$data$lib$system$ordered$set$$OrderedSet, store: Class, key: "rights", inverseKey: undefined, …}
source: ember$data$lib$system$relationships$state$belongs$to$$Belong

You can refer to the first post, where you can see groups, rights and source relationships in the model.

So again, why this one is not instantiated ? I don’t really understand.

Yeah that’s what i was guessing. It should be instantiated when you get it according to the docs but for some reason that doesn’t seem to be happening. It’s almost like it doesn’t recognize that relationship at all.

What happens if you look at relationshipByName for that model? That should tell you if the model knows it has that relationship or not.

Ok so this is getting weirder. The relationship is “here” but as you said it is not recognized, I printed what you asked :

Map {_keys: OrderedSet, _values: {…}, size: 4}
size: 4
_keys: OrderedSet
list: Array(4)
0: "groups"
1: "rights"
2: "source"
3: "applicationPasswords"

the details :

_values:
st497: {key: "groups", kind: "hasMany", type: "group", options: {…}, parentType: ƒ, …}
st498: {key: "rights", kind: "hasMany", type: "right", options: {…}, parentType: ƒ, …}
st499: {key: "source", kind: "belongsTo", type: "ldap", options: {…}, parentType: ƒ, …}
st500:
isRelationship: true
key: "applicationPasswords"
kind: "hasMany"
options: {async: true}
parentType: ƒ ()
type: "application-password"

Woah that is weird. Curious what would happen if you created a new record from the store and tried to do the same thing (e.g. will it lazily instantiate the ManyArray like it’s supposed to)… I don’t see why that would be different but who knows.

Hi again,

I managed to find the error, I named the file model with an ‘s’. Because of the naming convention, It wasn’t working. I renamed my file from application-passwords.js to application-password.js and now it is working.

The thing is I bumped into another strange error.

I’m trying to do the same thing as the first post, but I modified a bit of my code :

controller :

createApplicationPasswords: function(userAdded) {
      const currentUser = this.get('currentUser');

      this.set('errors.add_user', '');
      if (!(userAdded && userAdded.id !== 0)) {
        // TODO check 'auto-complete' component
        this.set('errors.add_user', this.get('intl').t('admin.groups.users.unknown'));
        return;
      }

      console.log(userAdded.id);

      const newAP = this.store.createRecord('application-password', {
        user: userAdded.id,
        passwordName: 'partner_id=',
        username: userAdded.login,
        password: utils.genRandomPassword(16),
        system: true,
      });
      newAP.set('user', userAdded.id);
      newAP.save().then((aP) => {
        currentUser.get('applicationPasswords').pushObject(aP);
        currentUser.save().catch(() => {
          this.get('toaster').error('Error');
        });
      }).catch((err) => {
        console.log(err);
        this.get('toaster').error('Error');
      });

This is how I save my application passwords :

  • userAdded variable is a user of my app which I get from my back-end and auto-complete helpers
  • userAdded.id = 1 in this example

The thing is, I am getting an error on model validation in my Go back-end because user: userAdded.id is null but when I print it, it’s equal to 1 and my back-end does not accept null ID of course.

See the request payload :

password: "hiding this"
passwordName: "hiding this"
system: true
user: null
username: "hiding this"

The error is catch is the ‘first’ catch from newAP.save().then((aP) => {.

As you can see I even try to set the user propertie like this : newAP.set('user', userAdded.id);

Ah yes the pluralization thing can be tricky, I’ve done that before. Very strange that it didn’t complain that the model type was invalid though. I feel like modern Ember probably would. Good catch!

Ember Data usually deals with full relationships/records. So instead of setting user to an id, try setting it to a full record and Ember Data should take care of the rest for you:

      const newAP = this.store.createRecord('application-password', {
        user: userAdded,
        passwordName: 'partner_id=',

Just to give you the bigger picture (I changed as you said) :

const newAP = this.store.createRecord('application-password', {
        user: userAdded,
        passwordName: 'partner_id=',
        username: userAdded.login,
        password: utils.genRandomPassword(16),
        system: true,
      });

and

 newAP.save().then((aP) => {
        currentUser.get('applicationPasswords').pushObject(aP);
        currentUser.save().catch(() => {
          this.get('toaster').error('Error');
        });
      }).catch((err) => {
        console.log('error thrown here :', err);
        this.get('toaster').error('Error');
      }).then((aPRecord) => {
        aPRecord.save();
      }).catch(() => {
        this.get('toaster').error('Error');
      }).then((aPRecord) => {
        currentUser.get('applicationPasswords').pushObject(aPRecord);
        currentUser.save();
      }).catch(() => {
        this.get('toaster').error('Error');
      });

In the dev console, the Ember Data about application-password is set but the field user is still equal to null so my back-end refuse to accept the requested payload

password: "hiding this"
passwordName: "hiding this"
system: true
user: null
username: "hiding this"

If I were debugging this my next step would be looking at the Network tab in your browser dev console and making sure the POST request had the right user id/attribute present. If it didn’t or it wasn’t formatted correctly you may need to address it somewhere in your serializer (depending on what’s wrong with it). If that looks right the the problem must be on the API end.