Search code examples
validationmeteormeteor-autoformmeteor-collection2

Skipping insert validation on Meteor.createUser with Collection2


I'm working on a Meteor App where users follow a multiple step registration process. They first sign up and then get through 3 customised forms before accessing a dashboard. I'm using Autoform on update-mode and Collection2 to validate the different forms. After signing up, the user updates the necessary values on each form and fields/input errors are handled by Collection2.

My problem is this: Although I started the project having all my fields and subfields set as optional, I'd like to make them mandatory so Collection2 also handle missing inputs. But when I remove the optional options, my forms are still updated correctly and now handle empty fields but users can't register anymore.

Exception while invoking method 'createUser' Error: First name is required

I'm currently calling Meteor.createUser client-side, I wonder if there is any way to prevent Meteor.createUser to check all non-optional fields on insert. I know I could call it server-side but I'd have to encrypt the password over submission and I'm not even sure I can bypass C2 validations from there.

It is quite important the user first signup and then can continue or leave and come back to finish to fill in the forms. I know I could use createUser on last form or put everything optional back and make some custom validations on each field but I'm looking for some "prettier" way. Any input would be greatly appreciated!


Solution

  • After many tests, I finally found a workaround. Having your mandatory fields set in optional nested schemas so the validation does not fail on insert.

    Also, make sure you don't have autovalues or values created from the very beginning in an optional nested schema otherwise it would create it and then trigger the validations (both were my case, I had an autovalue on a form-progression tracker which was set and updated on each new step).


    Here is a concrete example:

    Posts = new Mongo.Collection("posts");
    
    var Schema = {};
    Schema.Replies = new SimpleSchema({
        owner: {
            type: String
        },
        content: {
            type: String
        }
    });
    
    Schema.Posts = new SimpleSchema({
        createdAt: {
            type: Date,
            autoValue: function() {
                if (this.isInsert)
                    return new Date();
                else if (this.isUpsert)
                    return {$setOnInsert: new Date()};
                else
                    this.unset();
            },
            optional: true
        },
        content: {
            type: String
        },
        replies: {
            type: [Schema.Replies],
            optional: true
        },
        owner: {
            type: String,
            autoValue: function() {
                if (!this.isSet) {
                    return this.userId;
                }
            }
        },
    });
    
    Posts.attachSchema(Schema.Posts);
    

    So you can have a Post which can contain replies, or not. However, if you decide to add a reply, you have to fill in all the mandatory fields in the nested schema otherwise your update will be rejected. You can replicate this logic to anything (so in my case, having a Meteor.user being updated as our signup form continued). Hope it helps.