Waterline/SailsJs防止嵌套(关系)保存模型

Waterline/SailsJs prevent nested (relationship) save of model

本文关键字:关系 保存 模型 嵌套 SailsJs Waterline      更新时间:2023-09-26

我有一个与"Subject"具有多对一关系的"User"模型。

User.js

attributes: {
    subject: { model: 'subject' },
}

Subject.js

attributes: {
    name: { type: 'string', unique: true, required: true },
}

当我为用户"/User "调用蓝图创建函数并传入数据时:

{
    "name":"Test",
    "subject":{"name":"Do Not Allow"}
}

它创建了用户,也创建了Subject。然而,我不想让主题被创建,我只希望能够附加一个现有的。例如,我希望它拒绝使用上述数据创建主题,但允许使用以下数据附加主题。

{
    "name":"Test",
    "subject":1
}

我尝试添加一个策略(如下所示),但这只会阻止使用URL"/subject"创建主题,而不是上面所示的嵌套创建。

'SubjectController':{
    'create':false
}

编辑为了帮助理解这里发生了什么下面是它所经历的生命周期过程:

Before Validation of Subject
After Validation of Subject
Before Creating Subject
After Creating Subject
Before Validation of User
After Validation of User
Before Creating User
Before Validation of User
After Validation of User
After Creating User

可以看到,在验证和创建用户之前,它已经在验证和创建主题了

您希望在调用蓝图创建路由时避免创建关联对象。

创建一个策略(我将其命名为checkSubjectAndHydrate)并将其添加到policies.js文件中:

// checkSubjectAndHydrate.js
module.exports = function (req, res, next) {
  // We can create a user without a subject
  if (_.isUndefined(req.body.subject)) {
    return next();
  }
  // Check that the subject exists
  Subject
    .findOne(req.body.subject)
    .exec(function (err, subject) {
      if (err) return next(err);
      // The subject does not exist, send an error message
      if (!subject) return res.forbidden('You are not allowed to do that');
      // The subject does exist, replace the body param with its id
      req.body.subject = subject.id;
      return next();
  });
};
// policies.js
module.exports.policies = {
  UserController: {
    create: 'checkSubjectAndHydrate',
    update: 'checkSubjectAndHydrate',
  }
};

您应该传递主题id(例如1)而不是包含主题名称的对象(例如{ name: 'Hello, World!' }),因为它不一定是唯一的。

如果它是唯一的,你应该用它在beforeValidate中的id来替换它。

// User.js
module.exports = {
  ...
  beforeValidate: function (users, callback) {
    // users = [{
    //   "name":"Test",
    //   "subject":{"name":"Do Not Allow"}
    // }]
    async.each(users, function replaceSubject(user, next) {
      var where = {};
      if (_.isObject(user.subject) && _.isString(user.subject.name)) {
        where.name = user.subject.name;
      } else if(_.isInteger(user.subject)) {
        where.id = user.subject;
      } else {
        return next();
      }
      // Check the existence of the subject
      Subject
        .findOne(where)
        .exec(function (err, subject) {
          if (err) return next(err);
          // Create a user without a subject if it does not exist
          user.subject = subject? subject.id : null;
          next();
      });
    }, callback);
    // users = [{
    //   "name":"Test",
    //   "subject":1
    // }]
  }
};

您可以为主题创建自定义类型,并在模型中添加您的逻辑。我不能100%确定我理解了附件有时部分,但也许这可以帮助:

模型/User.js

module.exports = {
    schema: true,
    attributes: {
        name: {
            type: 'string'
        },
        subject: {
            type: 'json',
            myValidation: true
        }
    },
    types: {
        myValidation: function(value) {
            // add here any kind of logic...
            // for example... reject if someone passed name key
            return !value.name;
        }
    }
};

您可以在页面底部找到更多信息http://sailsjs.org/documentation/concepts/models-and-orm/validations。

如果我完全没有抓住重点…第二个选项是向模型中添加beforerecreate和beforeUpdate生命周期回调,如下所示:

模型/User.js

 module.exports = {
    schema: true,
    attributes: {
        name: {
            type: 'string'
        },
        subject: {
            type: 'json'
        }
    },
    beforeCreate: function (values, cb) {
        // for example... reject creating of subject if anything else then value of 1
        if (values.subject && values.subject !== 1) return cb('make error obj...');
        cb();
    },

    beforeUpdate: function (values, cb) {
        // here you can add any kind of logic to check existing user or current update values that are going to be updated
        // and allow it or not
        return cb();
    }
};

通过使用这个,你可以使用一个逻辑来创建,另一个逻辑来更新…等等…

您可以在这里找到更多信息:http://sailsjs.org/documentation/concepts/models-and-orm/lifecycle-callbacks

编辑

意识到你有关系的麻烦,在上面的例子中,我认为你正在处理json类型…

module.exports = {
    schema: true,
    attributes: {
        name: {
            type: 'string'
        },
        subject: {
            model: 'subject'
        }
    },
    beforeValidate: function (values, cb) {
        // subject is not sent at all, so we just go to next lifecycle
        if (!values.subject) return cb();
        // before we update or create... we will check if subject by id exists...
        Subject.findOne(values.subject).exec(function (err, subject) {
            // subject is not existing, return an error
            if (err || !subject) return cb(err || 'no subject');
            //
            // you can also remove subject key instead of sending error like this:
            // delete values.subject;
            //
            // subject is existing... continue with update
            cb();
        });
    }
};