Frage

In Sails.js 0.10 versuche ich Folgendes zu tun

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

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

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

Ich erhalte eine Fehlermeldung, wenn ich versuche, einen Benutzer zu erstellen, und SailsJS erkennt das Attribut „Profil“ nicht.Ich bin nicht sicher, ob Sails die verschachtelte JSON-Struktur unterstützt, und wenn ja, bin ich nicht sicher, wie ich sie strukturieren soll.

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

Ich habe Folgendes versucht, aber es ist auch fehlgeschlagen

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

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

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

Ich weiß, dass es in SailsJS 0.10 ein Attribut namens „JSON“ gibt, bin mir aber nicht sicher, wie das zu diesem Modul passt.

War es hilfreich?

Lösung

Waterline unterstützt die Definition verschachtelter Schemata nicht, Sie können jedoch das verwenden json Geben Sie ein, um eingebettete Objekte in Ihrem Modell zu speichern.Sie würden also Folgendes tun:

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

Und dann könnten Sie Benutzerinstanzen erstellen wie:

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

Der Unterschied besteht darin, dass die firstName Und lastName Felder werden nicht validiert.Wenn Sie das Schema des eingebetteten validieren möchten profile Wenn das Objekt Ihren Wünschen entspricht, müssen Sie es implementieren beforeValidate() Lebenszyklusrückruf in Ihrer Modellklasse:

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

Andere Tipps

Nachfolgend Antwort von @sgress454 Ich habe eine zusätzliche Logik erstellt, um dieses Problem zu lösen.

Da ich diese „verschachtelten Modelle“ mehr als einmal verwende, habe ich für diese einen Dienst mit einer Factory erstellt beforeValidade() Lebenszyklusrückrufe.


So sieht es aus:

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>


Und im Modell habe ich Folgendes:

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)

};


Ich weiß, dass es noch nicht perfekt ist, vielleicht sollte ich daraus einen Hook machen, aber ich bin immer noch verwirrt, wie ich das am besten machen kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top