Recibo el error "_id no está permitido por el esquema" cuando intento usar un formulario automático para actualizar una colección a través de un método ValidatedMethod.

Por lo que puedo ver en este ejemplo y el documentos oficiales no hay ninguna expectativa de que mi esquema incluya el campo _id, y no esperaría actualizar el id de una declaración de actualización, por lo que no tengo idea de por qué ocurre este error.

Si cambio de usar el método validado a escribir directamente en la colección (con un esquema adjunto a la colección que no tiene la identificación), todo funciona como se esperaba, así que supongo que el problema es con mi validación en mi ValidatedMethod.

¿Alguna idea de lo que estoy haciendo mal?

Plantilla: customer-edit.html

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

Plantilla 'código subyacente': 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;
    }
});

Actualizar método validado:

// 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);
    }
});

Esquema:

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
    }
});

Colección:

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);
2
tomRedox 28 ene. 2016 a las 19:18

2 respuestas

La mejor respuesta

Finalmente llegué al fondo de esto. El problema es que autoform pasa un objeto compuesto que representa la identificación del registro que se va a cambiar y también un modificador ($ set) de los datos, en lugar de solo los datos en sí. Entonces, la estructura de ese objeto está en la línea de:

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

Una vez que me di cuenta de eso, cambié mi método de actualización a este y todo funcionó como se esperaba:

// 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);
    }
});
4
tomRedox 29 ene. 2016 a las 17:57

Excelente. Tu publicación me ayudó cuando estaba luchando por encontrar cualquier otra información sobre el tema.

Para aprovechar su respuesta, si por alguna razón desea obtener los datos del formulario como un solo bloque, puede usar lo siguiente en AutoForm.

type="method" meteormethod="myValidatedMethodName"

Su método validado entonces podría verse así:

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

NB: El método Schema.validate () requiere un Objeto, no el modificador como antes.

No tengo claro si hay ventajas claras para cualquiera de los métodos en general.

El type = "method-update" es obviamente la forma en que desea actualizar los documentos porque obtiene el modificador. El "método" type = parece ser la mejor manera de crear un documento nuevo. Probablemente también sea la mejor opción en la mayoría de los casos en los que no tiene la intención de crear un documento a partir de los datos del formulario.

1
Xava 16 abr. 2016 a las 12:59