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

时间:2016-06-30 15:32:41

标签: javascript node.js orm sails.js waterline

我有一个模型“用户”,与“主题”有多对一的关系。

user.js的

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

Subject.js

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

当我为用户“/ user”调用蓝图创建函数并传入数据时:

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

它创建用户并创建主题。但是我不想允许创建主题,我只希望能够附加现有主题。例如,我希望它拒绝使用上述数据创建的主题,但允许使用以下数据附加主题。

{
    "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

正如您所看到的那样,在验证或创建用户之前,它正在验证和创建主题。

3 个答案:

答案 0 :(得分:2)

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

制定政策(我将其命名为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',
  }

};

答案 1 :(得分:0)

您可以为主题创建自定义类型,并在模型中添加逻辑。我不是百分百肯定我理解附着有时是部分,但也许这可能会有所帮助:

模型/ 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找到更多信息。

如果我完全错过了这一点......第二个选项是将beforeCreate和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();
        });
    }
};

答案 2 :(得分:0)

您应该传递主题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
    // }]
  }

};