-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added uniqueness validator for models #227
Added uniqueness validator for models #227
Conversation
Wouldn't this be better handled at the DB level with a UNIQUE constraint on that column? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 small change requested
src/granite/validation_helpers.cr
Outdated
|
||
macro validate_uniqueness(field) | ||
validate {{field}}, "#{{{field}}} should be unique", -> (model: self) do | ||
# If there is no value than ignore this validation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove the comment
|
||
personUniqueness2.errors[0].message.should eq "name should be unique" | ||
|
||
# Should be valid because it should not check uniqueness on itself |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make a separate test for this use case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ofcourse
@Blacksmoke16 You could also do that indeed. But in some use cases you want to have an uniqueness validation error like on a sign up page. If you post the form it will give the error already without having the database throwing the error. So you can show the error on the form with the other validation errors if there are any. |
Take this for example: with a unique constraint on class User < Granite::Base
adapter mysql
table_name users
primary user_id : Int64, auto: false
field! user_name : String
end User.create(user_id: 1.to_i64, user_name: "foo") # Saves successfully, no errors
Isn't this pretty much what your validate uniqeness does? Or am i missing a specific use case? |
@Blacksmoke16 Yes you are totally right. But if you have a model that you validate. So let's take as an example User. class User < Granite::Base
# Adapters
adapter pg
# Table
table_name users
# Fields
field username : String
field password : String
field full_name : String
timestamps
# Validations
validate_not_blank :username
validate_not_blank :password
validate_not_blank :full_name
end
class Controller < Amber::Controller::Base
def example
user = User.new params
if user.valid?
user.save
respond_with {
json user
}
else
# Do something with the user.errors
# For example in the view
end
end
end If you now look at the else statement you can do something with the validation errors. ["password must not be blank", "username must not be blank", "full_name must not be blank"] If the user than fix the error and submit again it's going to get the database constraint error you described in your comment. So your html error handling can be the same for the uniqueness error instead of having another error handling for the uniqueness constraint. And in my API i return the errors like this {
"message": {
"password": [
"password must not be blank"
],
"username": [
"username must be unique"
]
},
"code": 400
} |
Alright yea, makes sense. Good to see someone using my other validation helpers ;) 👍 |
I updated the README.md with the new validator option. I see that the documentation in the docs folder is not the same as the README.md. Is the documentation i added enought or do i need to do more? |
@drujensen Could you rereview please :). I changed the things you mentioned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥇
@Thellior It's fine for now. @faustinoaq requested we move to gitbooks and I agree. Its something we should do and replace the readme to point to that instead of maintaining two sets of documents. |
This is a good addition to the validation libraries, but it is simply not a replacement for database constraints, and can never be. It's very easy for a user to cause a race condition and create two records by double-clicking a submit button. |
@robacarp I totally agree but i think you always should have database validations and model validations. This is just an addition for nice error handling |
What is done
Explaination
The validator add a feature to the validator helpers that verify if the field value is not already in use. The validator will try to fetch one record that has the same field value. If the value does not exist in the database than the validation will succeed. If the value does exist in the database it will fail if the record is not the same as the model that is being updated.