Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass in an existing document to update, passing model breaks validatation #3

Closed
zeroasterisk opened this issue May 12, 2016 · 12 comments
Assignees
Labels
Type: Bug Bug reports and their fixes

Comments

@zeroasterisk
Copy link
Contributor

How do you pass in an existing document to update?

When I try to pass it in as a model - values update in the form but validation no longer throws errors (I assume because it's not validating the new data??)

@zeroasterisk zeroasterisk changed the title Pass in an existing document to update Pass in an existing document to update, passing model breaks validatation May 12, 2016
@radekmie
Copy link
Contributor

Actually it is validating new model. Could you share a not working example?

@radekmie
Copy link
Contributor

I'll close it for now. If problem persist, please let me know.

@radekmie radekmie added the Type: Bug Bug reports and their fixes label May 28, 2016
@radekmie radekmie self-assigned this May 28, 2016
@todda00
Copy link
Contributor

todda00 commented Jun 28, 2016

I am also experiencing this issue, when I use <AutoForm schema={userSchema} model={user} onSubmit={doc => console.log(doc)} > I get no validation at all, but when I do not include a model: <AutoForm schema={userSchema} onSubmit={doc => console.log(doc)} > It validates the form against the schema.

@radekmie
Copy link
Contributor

Could you share some more code, @todda00?

@todda00
Copy link
Contributor

todda00 commented Jun 29, 2016

I was able to determine the issue is with a document which has collection helpers (https://github.com/dburles/meteor-collection-helpers) on it, providing prototype functions on the object.

The following is my user schema and collection helpers:

import { Meteor } from 'meteor/meteor';
import {SimpleSchema} from 'meteor/aldeed:simple-schema';
import AddressSchema from '/lib/collections/addressSchema';
import moment from 'moment';

const Guardian = new SimpleSchema({
  firstName:{
    type: String,
    optional: true
  },
  lastName:{
    type: String,
    optional: true
  },
  phone:{
    type: String,
    optional: true,
    min:10
  },
  email:{
    type: String,
    regEx:  SimpleSchema.RegEx.Email,
    optional:true
  }
});

const schema = new SimpleSchema({
  _id:{
    type: String,
    regEx: SimpleSchema.RegEx.Id
  },
  createdAt: {
    type: Date
  },
  services: {
    type: Object,
    blackbox: true,
    optional: true
  },
  roles:{
    type: Object,
    blackbox: true,
    optional : true
  },
  emails:{
    type: [Object]
  },
  'emails.$.address':{
    type: String,
    regEx:  SimpleSchema.RegEx.Email
  },
  'emails.$.verified':{
    type: Boolean
  },
  profile:{
    type: Object
  },
  'profile.firstName':{
    type: String
  },
  'profile.lastName':{
    type: String
  },
  'profile.phone':{
    type: String,
    optional: true,
    min:10
  },
  'profile.address':{
    type: AddressSchema,
    optional:true
  },
  'profile.gender':{
    type: String,
    allowedValues:['male','female'],
    optional: true
  },
  'profile.birthdate':{
    type: Date,
    max (){
      return moment().subtract(13,'years').toDate();
    },
    optional: true
  },
  'profile.primaryGuardian':{
    type: Guardian,
    optional:true
  },
  'profile.secondaryGuardian':{
    type: Guardian,
    optional:true
  }
});

Meteor.users.attachSchema(schema);

Meteor.users.helpers({
  fullName() {
    return this.profile.firstName + ' ' + this.profile.lastName;
  },
  formatedBirthdate(format='MM/DD/YYYY'){
    if (this.profile === undefined || this.profile.birthdate === undefined) return null;
    return moment(this.profile.birthdate).format(format);
  }
});

export default Meteor.users;

I am using Matra, here is my container:

import {useDeps, composeAll, composeWithTracker, compose} from 'mantra-core';

import Register from '../components/register.jsx';
import RegisterPlayerBasicInfo from '../components/register_player_basic_info.jsx';
import RegisterUserType from '../components/register_user_type.jsx';
import RegisterAccount from '../components/register_account.jsx';

export const composer = ({context, clearLocalState, step}, onData) => {
  const {Meteor, Collections, LocalState} = context();

  const userSchema = Meteor.users.simpleSchema();
  const error = LocalState.get('error.user.register');
  let topText, StepComponent, percentage = 0;
  switch(step){
    case 'RegisterUserType':
      percentage = 0;
      topText = "First, tell us what you're looking for.";
      StepComponent = RegisterUserType;
      break;
    case 'RegisterAccount':
        percentage = 0;
        topText = "Great! Let's get started.";
        StepComponent = RegisterAccount;
        break;
    case 'RegisterPlayerBasicInfo':
      percentage = 25;
      topText: "To get the best possible matches, complete your profile!",
      StepComponent = RegisterPlayerBasicInfo;
      break;
  }

  //Load the user into context if logged in
  const uid = Meteor.userId();
  if (Meteor.subscribe('users.single',uid).ready()){
    const user = Meteor.users.findOne({_id:uid});
    onData(null, {userSchema, error, topText, percentage, StepComponent, user});
  }

  //clear shared LocalStates when unmounting the component
  return clearLocalState;
};

export const depsMapper = (context, actions) => ({
  context: () => context,
  clearLocalState: actions.register.clearLocalState,
  // updateField: actions.register.updateField,
});

export default composeAll(
  composeWithTracker(composer),
  useDeps(depsMapper)
)(Register);

The Register component has some common elements, but nothing to do with this issue, so I will just show you the component which shows the form (In reality I am using a mix of custom and AutoField and other types, but using the autogenerated AutoForm has the same issue, so I will simplify my example):

import React from 'react';
import {AutoForm}  from 'uniforms-bootstrap4';

class RegisterPlayerBasicInfo extends React.Component {
  render(){
    const {user, userSchema, error} = this.props;
    return(
      <div className='text-xs-left'>
        <AutoForm schema={userSchema} model={user} onSubmit={doc => console.log(doc)} />
      </div>
    );
  }
}
export default RegisterPlayerBasicInfo;

This all works when I remove the collection helpers. Here is the user object with collection helpers:
localhost_3005_register_player_basic-info

And here is the user object without collection helpers:
localhost_3005_register_player_basic-info

@zeroasterisk
Copy link
Contributor Author

HA! yes indeed - I also use meteor-collection-helpers and that was likely the cause of the problem for me too...

@radekmie
Copy link
Contributor

It's interesting, but it seems that's a problem of SimpleSchema itself. I'll try to find out, what's going on.

@radekmie
Copy link
Contributor

radekmie commented Jun 29, 2016

Unfortunately (is it?) it's a SimpleSchema problem. It simply does nothing with non-plain objects. There's also an issue for that. Unluckily, it's almost one year old.

@todda00
Copy link
Contributor

todda00 commented Jun 29, 2016

I was able to get this to work if I convert my object to a basic object using this (uses lodash's forOwn):

    const basicObj = {};
    _.forOwn(user,(val,key)=>{
      basicObj[key] = val;
    });

Then using basicObj as the model to validate, it works. Would this be a bad idea to incorporate into this project, stripping out any model's inherited properties, since SimpleSchema will ignore the whole object otherwise?

@radekmie
Copy link
Contributor

You can simplify it - {...doc} will suffice.


I think it's not necessary because it will cause additional overhead if you are not using prototype-based documents.

@zeroasterisk
Copy link
Contributor Author

I certainly think this is a gotcha worth a bit of code in package, to avoid users having to run into issues trying to use the package... especially since, inside the package, it is basically only required when ingesting the initial model

@radekmie
Copy link
Contributor

 getValidator (options = {clean: true}) {
     const validator = this.schema.validator(options);
-    return model => validator(cloneDeep(model));
+    return model => validator(cloneDeep({...model}));
 }

This change in SimpleSchemaBridge should suffice - striping prototype is needed only during SimpleSchema validation.

@radekmie radekmie reopened this Jun 30, 2016
@radekmie radekmie moved this to Closed in Open Source Nov 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Bug reports and their fixes
Projects
Archived in project
Development

No branches or pull requests

3 participants