tomRedox
tomRedox

Reputation: 30443

MDG ValidatedMethod with Aldeed Autoform: "_id is not allowed by the schema" error

I'm getting the error "_id is not allowed by the schema" when trying to use an autoform to update a collection via a ValidatedMethod.

As far as I can see from this example and the official docs there is no expectation for my schema to include the _id field, and I wouldn't expect to be updating the id from an update statement, so I have no idea why this error is happening.

If I switch from using the validated method to writing directly to the collection (with a schema attached to the collection that doesn't have the id in) everything works as expected, so I'm assuming the issue is with my the validate in my ValidatedMethod.

Any idea what I'm doing wrong?

Template: customer-edit.html

<template name="updateCustomerEdit">
    {{> quickForm
        collection="CustomerCompaniesGlobal"
        doc=someDoc
        id="updateCustomerEdit"
        type="method-update"
        meteormethod="CustomerCompanies.methods.update"
        singleMethodArgument=true
    }}
</template>

Template 'code behind': customer-edit.js

Template.updateCustomerEdit.helpers({

    someDoc() {
        const customerId = () => FlowRouter.getParam('_id');
        const instance = Template.instance();

        instance.subscribe('CustomerCompany.get', customerId());

        const company = CustomerCompanies.findOne({_id: customerId()});
        return company;
    }
});

Update Validated Method:

// The update method
update = new ValidatedMethod({

    // register the name
    name: 'CustomerCompanies.methods.update',

    // register a method for validation, what's going on here?
    validate: new SimpleSchema({}).validator(),

    // the actual database updating part validate has already been run at this point
    run( newCustomer) {
    console.log("method: update");
        return CustomerCompanies.update(newCustomer);
    }
});

Schema:

Schemas = {};

Schemas.CustomerCompaniesSchema = new SimpleSchema({

    name: {
        type: String,
        max: 100,
        optional: false
    },

    email: {
        type: String,
        max: 100,
        regEx: SimpleSchema.RegEx.Email,
        optional: true
    },

    postcode: {
        type: String,
        max: 10,
        optional: true
    },

    createdAt: {
        type: Date,
        optional: false
    }
});

Collection:

class customerCompanyCollection extends Mongo.Collection {};

// Make it available to the rest of the app
CustomerCompanies = new customerCompanyCollection("Companies");
CustomerCompaniesGlobal = CustomerCompanies;

// Deny all client-side updates since we will be using methods to manage this collection
CustomerCompanies.deny({
    insert() { return true; },
    update() { return true; },
    remove() { return true; }
});

// Define the expected Schema for data going into and coming out of the database
//CustomerCompanies.schema = Schemas.CustomerCompaniesSchema

// Bolt that schema onto the collection
CustomerCompanies.attachSchema(Schemas.CustomerCompaniesSchema);

Upvotes: 2

Views: 1228

Answers (2)

Xava
Xava

Reputation: 39

Excellent. Your post helped me out when I was struggling to find any other information on the topic.

To build on your answer, if for some reason you want to get the form data as a single block you can use the following in AutoForm.

type="method" meteormethod="myValidatedMethodName"

Your validated method then might look something like this:

export const myValidatedMethodName = new ValidatedMethod({
  name: 'Users.methods.create',
  validate(insertDoc) {
    Schemas.NewUser.validate(insertDoc);
  },
  run(insertDoc) {
    return Collections.Users.createUser(insertDoc);
  }
});

NB: The Schema.validate() method then requires an Object, not the modifier as before.

I'm unclear if there are any clear advantages to either method in general.

The type="method-update" is obviously the way you want to go for updating documents because you get the modifier. The type="method" seems to be the best way to go for creating a new document. It would likely also be the best option in most cases where you're not intending to create a document from the form data.

Upvotes: 1

tomRedox
tomRedox

Reputation: 30443

I finally got to the bottom of this. The issue is that autoform passes in a composite object that represents the id of the record to be changed and also a modifier ($set) of the data, rather than just the data itself. So the structure of that object is along the lines of:

_id: '5TTbSkfzawwuHGLhy',
modifier:
{ 
  '$set':
    { name: 'Smiths Fabrication Ltd',
      email: '[email protected]',
      postcode: 'OX10 4RT',
      createdAt: Wed Jan 27 2016 00:00:00 GMT+0000 (GMT Standard Time) 
    } 
} 

Once I figured that out, I changed my update method to this and everything then worked as expected:

// Autoform specific update method that knows how to unpack the single
// object we get from autoform.
update = new ValidatedMethod({

    // register the name
    name: 'CustomerCompanies.methods.updateAutoForm',

    // register a method for validation.
    validate(autoformArgs) {
        console.log(autoformArgs);
        // Need to tell the schema that we  are passing in a mongo modifier rather than just the data.
        Schemas.CustomerCompaniesSchema.validate(autoformArgs.modifier , {modifier: true});
    },

    // the actual database updating part
    // validate has already been run at this point
    run(autoformArgs)
    {
        return CustomerCompanies.update(autoformArgs._id, autoformArgs.modifier);
    }
});

Upvotes: 4

Related Questions