Loopback: Validators defined in models .js file does not work on submodels

Created on 25 Jun 2015  路  17Comments  路  Source: strongloop/loopback

Hello, I'm using isomorphic loopback in combination with React.js and trying to use validators on client side. Everything works well with server models, but not work with local ones.

User.json

{
  "name": "User",
  "base": "PersistedModel",
  "persistUndefinedAsNull": true,
  "trackChanges": true,
  "properties": {
    "id": {
      "id": true,
      "type": "string",
      "required": true,
      "defaultFn": "guid"
    },
    "name": {
      "type": "string",
      "required": true
    }
  }
}

User.js

export default (User) => {
  User.validatesLengthOf('name', { min: 5 }) // name should be longer than or equal to 5 chars
}

LocalUser.json

{
  "name": "LocalUser",
  "base": "User",
  "enableRemoteReplication": true
}

browser code

import { models } from 'loopback-client'

// ----- Remote model ------

let user = models.User({
  name: 'Bob' // 3 chars, 5 is minimum
})

user.isValid() // false

// ----- Local model ------

let localUser = models.LocalUser({
  name: 'Bob'
})

localUser.isValid() // true, should be false

I don't think it's expected behaviour.

Thank you.

edit:
It's interesting that required: true validator from User.json file works well on client (maybe because base: "User" in LocalUser.json ignore User.js file?)

let localUser = models.LocalUser({
  name: ''
})

localUser.isValid() // false

When I change it to required: false, isValid() returns true.

edit 2:
I found dirty solution. Creating LocalUser.json with same content as User.json solve this problem (after that length validator works).

bug major

All 17 comments

Can you provide a link to a test project on Github? See https://github.com/strongloop/loopback/wiki/Issues#bug-report

Hello

I created a Fork (https://github.com/Kr0san89/loopback-sandbox) like in the description, i was the guy who did the 2nd issue #1500 sorry for that.
It is easy to reproduce just start it. If you send a post on /As
{
"test": "a"
}
you get "message": "The A instance is not valid. Details: test test is too short (value: \"a\").",
Which is as expected, because of the validation rule
But if you Post on /Bs which has base Class A the same Message
{
"test": "A"
}
It is working without Error ;) I guess the validation should also work for subclasses?
Thanks

Thanks for providing the repo. Will look into it.

Cool, did the repo help to reproduce it for you?

@Kr0san89 Yes, I managed to reproduce it. Escalating to bug as I've seen a few duplicate issues now.

Same issue. comment here just to trace this bug and this https://github.com/strongloop/loopback/issues/1588

+1 Just ran into this issue. If the "required" property is not set or set to false in the model it should not fail validation checks when the property is undefined on save. We already have the validatesPresenceOf method to explicitly check for required properties. I do not want to create custom validators that mirror built in methods except have a null check. This is also helpful if you want to enforce a minimum length for a property when it _is_ provided, but it is not an error that it is not provided.

Thank you.

I think the workaround solution is to define the validators from withing MyModel.setup. That method is called whenever a model is subclassed, which will cause the validators to be defined again on the new model.

// common/models/parent.js
module.exports = function(Parent) {
  Parent.setup = function() {
    Parent.base.setup.apply(this, arguments);

    Parent.validatesPresenceOf('name');
  };

  // Note that the setup function is not run automatically for the actual model it's defined on
  Parent.setup();
};

Having said that, we should still fix this issue.

Had some discussion and test implementation and came to the conclusion that we probably should not be inheriting the validations by model creation, but to encourage users to use the Model.setup() function as a constructor for the model _(this is not really well documented, or maybe not documented at all)_ and i think is what led to users having subModel inherit issues. Basically model on submodels are already being rebuilt, but if we also inherit we will run into issues where validations gets inherited then rebuilt and end up with duplication and there aren't easy ways to remove validation after the fact.

The creation of sub-models actually calls the parents setup function, which gives us the ability to add logic to the child-model's constructor, which also means the ability to build those validations on the childModel.

/cc @bajtos @raymondfeng

@davidcheung, did you create a doc issue for @crandmck?

@richardpringle good idea
https://github.com/strongloop/loopback/issues/2332

Closing issue now

@bajtos your workaround is not working for me

My model herarchy is the next one:

PersistedModel -> BaseModel -> BusinessOwnerActionModel (workaround here) -> BusinessModel (when saving it doesn't throw an error)

@acabrera91 can you fork the loopback-sandbox and reproduce the issue in your forked repo, then provide a link?

It might be a good idea to open a new issue too since this one is closed.

Additionally: issue #1588 is closed as duplicate of this issue. But the problem described there is still seems unsolved: validation rules are still applied in not required properties.

Somewhat related to this - loopback-component-passport/issues/173 I basically need an option to override or suppress email validation from the base model. Is there a way to do this?

@git2g I have the same problem. I added the following line in my app.start function:

delete app.models.User.validations.email;

It not the best solution but it does suppress the email validation.

Source:
https://github.com/strongloop/loopback/issues/879

Thanks @flam312 - wish they resolved the issue by providing a custom validatorFn for the base Email model. But I guess this will have to do for now

Was this page helpful?
0 / 5 - 0 ratings