Question

Dans sails.js 0.10, j'essaie de faire ce qui suit

// user.js
module.exports = {
  attributes: {

    uuid: {
        type: 'string',
        primaryKey: true,
        required: true
     } ,
     profile: {

        firstname: 'string',
        lastname: 'string',
        birthdate: 'date',
        required: true
     }
  }
};

Je reçois une erreur lorsque j'essaie de créer un utilisateur et sailsJS ne reconnaît pas l'attribut "profil".Je ne sais pas si Sails prend en charge la structure JSON imbriquée, et si c'est le cas, je ne sais pas comment la structurer.

error: Sent 500 ("Server Error") response
error: Error: Unknown rule: firstname

J'ai essayé ce qui suit mais cela a également échoué

// user.js
module.exports = {
  attributes: {

    uuid: {
        type: 'string',
        primaryKey: true,
        required: true
     } ,
     profile: {

        firstname: {type: 'string'},
        lastname: {type: 'string'},
        birthdate: 'date',
        required: true
     }
  }
};

Je sais qu'il existe un attribut appelé "JSON" avec sailsJS 0.10, mais je ne sais pas comment cela s'adaptera à ce module.

Était-ce utile?

La solution

Waterline ne prend pas en charge la définition de schémas imbriqués, mais vous pouvez utiliser l'option json tapez pour stocker les objets incorporés dans votre modèle.Donc tu ferais :

profile: {
    type: 'json',
    required: true
}

Et puis vous pouvez créer des instances utilisateur telles que :

User.create({profile: {firstName: 'John', lastName: 'Doe'}})

la différence est que le firstName et lastName les champs ne seront pas validés.Si vous souhaitez valider que le schéma du système intégré profile l'objet correspond à ce que vous voulez, vous devrez implémenter le beforeValidate() rappel du cycle de vie dans votre classe de modèle :

attributes: {},
beforeValidate: function(values, cb) {
    // If a profile is being saved to the user...
    if (values.profile) {
       // Validate that the values.profile data matches your desired schema,
       // and if not call cb('profile is no good');
       // otherwise call cb();
    }
}

Autres conseils

Suivant @ réponse sgress454 J'ai créé une logique supplémentaire pour résoudre ce problème.

Comme j'utilise ces "modèles imbriqués" plus d'une fois, j'ai créé un service avec une usine pour ceux-ci. beforeValidade() rappels du cycle de vie.


Voici à quoi ça ressemble :

var _ = sails.util;
var WLValidationError = require('../../node_modules/sails/node_modules/waterline/lib/waterline/error/WLValidationError.js');


function validationError(invalidAttributes, status, message) {
  // Wrapper to helo with validation Errors
  return new WLValidationError({
      invalidAttributes: invalidAttributes,
      status: status,
      message: message
    }
  );
}


function fulfillJSON(attrValues, innerName, innerAttr) {
  // Helper to get default values into the JSON
  // Work with recurrency for arrays
  if (_.isArray(attrValues)) {
    return attrValues.map((attrVal) => {
      return fulfillJSON(attrVal, innerName, innerAttr);
    });
  }

  innerValue = attrValues[innerName];
  // Treat empty values
  if (innerValue == null) {
    // Check to see if it's required
    if (!innerAttr.required) {
      // If not required, try to set the defult value
      innerValue = innerAttr.defaultsTo;
    }
  }

  return attrValues;
}


function validateJSON(attrValues, innerName, innerAttr, invalidAttr, index) {
  // Helper to get error messages if it's not valid
  // Work with recurrency for arrays
  if (_.isArray(attrValues)) {
    invalidAttr = invalidAttr || {};
    _.each(attrValues, (attrVal) => {
      invalidAttr = validateJSON(attrVal, innerName, innerAttr, invalidAttr, attrValues.indexOf(attrVal));
    });
    return invalidAttr;
  }

  invalidMessage = "";

  innerValue = attrValues[innerName];
  // Treat empty values
  if (innerValue == null) {
    // Check to see if it's required
    if (innerAttr.required) {
      invalidMessage += '\n`' + innerName + '` is required!'
    };
  } else
  // Check if it has the right data type
  if (innerAttr.type) {
    if (typeof innerValue !== innerAttr.type) {
      invalidMessage += '\n`' + innerName + '` should be of type `' + innerAttr.type + '`!'
    };
  }

  if (invalidMessage != "") {
    invalidAttr = invalidAttr || {};
    innerInvalid = invalidAttr[innerName];

    if (innerInvalid != null && !_.isArray(innerInvalid)) {
      // Create an array if this attribute already have errors
      innerInvalid = [innerInvalid]
    };
    if (_.isArray(innerInvalid)) {
      // If it's an array, push new errors
      innerInvalid.push({
        index: index,
        field: innerName,
        value: innerValue,
        message: invalidMessage
      });
    } else {
      // If it's the first error, just create the object
      innerInvalid = {
        index: index,
        field: innerName,
        value: innerValue,
        message: invalidMessage
      };
    }

    invalidAttr[innerName] = innerInvalid;
  }
  return invalidAttr;
}


module.exports = {
  validateJSONFactory: function(jsonAttrs) {

    return function(values, cb) {
      // Object to store possible errors
      var invalidAttributes;

      // Go through each attibue trying to find json
      _.each(jsonAttrs, (attrSpecs, attrName) => {
        // Object to store specific attribute errors
        var invalidAttr;

        // Get the values to be validated
        attrValues = values[attrName]
        try {
          attrValues = JSON.parse(attrValues);
        } catch(e) {
          // console.log("Couldn't parse object, ignoring for now!")
          invalidAttributes[attrName] = {
            message: "Couldn't parse object!"
          };
          return false;
        }

        // Check if the specs are those of arrays
        if (_.isArray(attrSpecs)) {
          attrSpecs = attrSpecs[0];
          // Treat should be arrays
          if (!_.isArray(attrValues)) {
            attrValues = [attrValues];
          }
        }

        //Go through the specs in order to do some validation
        _.each(attrSpecs, (innerAttr, innerName) => {
          attrValues = fulfillJSON(attrValues, innerName, innerAttr);
          invalidAttr = validateJSON(attrValues, innerName, innerAttr, invalidAttr);
        });

        // Overload initial value, give back as string, the same way we got it!
        // values[attrName] = JSON.stringify(attrValues)
        values[attrName] = attrValues;

        // Make errors available outside
        if (invalidAttr != null){
          invalidAttributes = invalidAttributes || {};
          invalidAttributes[attrName] = invalidAttr;
        }

      }) // </each>

      if (invalidAttributes != null) {
        return cb(validationError(invalidAttributes));
      }

      return cb();

    } // </return function>
  } // </fulfillJSONFactory>
}  // </module.exports>


Et dans le modèle j'ai ça :

const jsonAttrs = {
  profile: {
    // Here you can add some specifications for your nested attributes
    // If you wish, you can have a list of profiles by wrapping this inner object in an array
    firstName: {
      type: 'string',  // `type` will be used in a `typeOf` comparison
      required: true  // `required` will check if the value is present
      // defaultsTo: 'John'  -  is also an option and will bring this value if none is given
      // more options can be added here, you just need to implement some logic on the service
    },
    lastName: {
      type: 'string',
      required: true
    }
  }
}


module.exports = {

  attributes: ModelService.complete({
    profile: {
      // Note that you don't need anything in here
    }
  }),

  beforeValidate: ModelService.validateJSONFactory(jsonAttrs)

};


Je sais que ce n'est pas encore parfait, je devrais peut-être en faire un crochet, mais je ne sais toujours pas quelle est la meilleure façon de le faire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top