Ruby Validation Methods

Greetings Mate,

In this article, you will learn how to validate data in Ruby on Rails. Validations allow us to make sure that data meets a set of requirements before it's saved to the database. You can think of them as rules that our data must follow. We could validate data every time a form is submitted, in other words, put our validation code in our controllers, but that would make it so that the rules are only enforced when we go through one of those controller actions. And then we'd be repeating ourselves every time we had to go through a controller that made updates to the same database tables.
It's much better to enforce the rules all the time globally in our application. And since this concerns the application's interaction with the database, the model is the best place for it. That way the rules will be enforced right at the doorway to the database. So we'll use ActiveRecord::Validations to define these validation rules inside our models. They'll become part of the intelligence of the model, and can be automatically checked anytime the model goes to save the data to the database. If the data doesn't follow the validation rules, then the model will refuse to complete the save, and also keep track of the errors, so that we can review them and give the user the opportunity to fix them.

In this movie, we're gonna look at the validation methods that ActiveRecord::Validations provides for us to use. In the next movie, we'll use them inside our simple CMS application. In total, there are ten validation methods that we can use. We're gonna go through each one of them. The first one we'll look at is going to be validates_presence_of. The way we used it was we went into our class for the subject, and we added a line that said validates_presence_of, and then we used the symbol for the name, the attribute that we wanted to validate.

That lets the validation know which attribute we want to validate the presence of. The validation also takes a second argument which we didn't use, which is a hash of options for configuring its behaviour. Almost all of the validations work this same way. They take an attribute, followed by a hash of options. Validates_presence_of makes sure that the attribute is not blank. Blank in rails encompasses nil, false, an empty string, a string with only spaces in it, and empty array, and an empty hash. If we add this validation, and then we submit with an attribute that's considered blank, that attribute will be marked with an error saying name can't be blank.


We can customise the last part of that message by passing in a new message in the options hash. The next validation we'll look at is validates_length_of. Here we're not just interested in the fact that there is a value, we're interested in how long the value is. How many characters it has. In this case, we'll have to pass in something to the options hash so it knows what we're looking for. So validates_length_of name, and then we'd say is and we could pass in whatever length ought to be. That would be if we wanted a precise length. Or we could use minimum, or maximum, or we could pass in both minimum and maximum to make sure it's between two numbers.
The shorthand for that is within, and in is a synonym for within. Instead of a single message for validates_length_of, there are actually three different messages that you can customise. Wrong length, too short, and too long. Notice that each one of them does have a special count variable that's being inserted inside of them. And that value will be drawn from the definition that you provide when you put the validation in.Next, we'll look at validates_numericality_of. Here we're making sure that something is a number, either an integer or a floating point number.

In addition to checking that it is a number, you can also add additional validations to check that the number is equal to, greater than, less than, greater than or equal to, less than or equal to. Or you can test if it's odd and even, or only let it be an integer, in other words, not allow floating point numbers. In every case, the default message is gonna be is not a number, so you'd likely want to customise it for those other options. The next validation is validates_inclusion_of. Here we have a list of choices, and we wanna make sure that the value of this attribute is in that set of choices.

In other words, it's included in that set. You would use it with the option in, followed by an innumerable object, such as an array or a range. If it doesn't pass the validation, the error message will say that this attribute is not included in the list. 

We have the opposite of that too with validates_exclusion_of. It does the exact same thing, but it makes sure that the value of the attribute is not in the list, and the default message for that is reserved. Then we have validates_format_of, where we can examine the value of an attribute to validate its format, and we do that using a regular expression.

So you would pass in the option with, and then the regular expression that you want to use. For example, if we need the value to be in the format of three letters followed by three numbers followed by three more letters, we could write a regular expression that made sure it was in that format. If not, it would fail the validation with the message is invalid. This is especially handy for checking email addresses and URLs to make sure they're in the correct format. And then we have validates_uniqueness_of. This ensures that the value is not already in the database.

A classic case for this is the username. We wanna make sure that a username can only exist one time in the database. So before we save the username John Doe to the database, we need to actually do a database query to see if there are any other John Does that are in the database. So keep that in mind. Validates_uniqueness_of, unlike the other validations, will make a database call while it's doing its job. It's the only way we can know whether that value already exists. We can pass in an option for whether the check should be case sensitive, and you can also pass in another option for the scope.

The idea here is that we might not be saying that John Doe is not allowed anywhere. It might only be disallowed in a certain scope, so company ABC could have a John Doe, and company XYZ could also have a John Doe. In that case, the scope might be the company ID.What validates_uniqueness_of is it takes that column that we provide for the scope and uses it in its query it is constructing. And the message, if it already exists in the database is has already been taken. Next, we have validates_acceptance_of.
This one is not tremendously useful. The idea here is that when we're filling out a form, we might want a user to check a box agreeing to something, like the terms of service. Validates_acceptance_of makes sure that that checkbox got checked. It does one other thing for you besides that. Because it's something like the terms of service, it might be that this attribute is not even stored in the database. We just want the person to agree to it on the form, but then we're not gonna store it after that. So you don't actually have to have a column in your table for it. If you don't, validates_acceptance_of will create a virtual attribute, and it will use that.

You can pass in the option accept, which is what value you're looking for. By default, that's going to be the string 1, because that's what the checkbox will send in the form. And the default message is must be accepted. 
The next one has a very similar sounding name, but it does something very different. The idea behind validates_confirmation_of is making sure that the user typed the data correctly by asking them to enter it a second time. So you've probably seen this before, where it says enter your password, and then you enter your password a second time.

Or you enter your email address and then enter your email address a second time. It does the same kind of virtual attribute that validates_acceptance_of does. We don't need to save their email confirmation to the database, so instead, it creates a virtual attribute, just long enough to make sure that it matches the original attribute. So for example, if we had validates_confirmation_of email, the virtual attribute would be called email confirmation, and then email and email confirmation would have to match or else it would fail validations.Now there's one additional important point that you need to know about, which is that it only runs this validation if the confirmation attribute has been set to something.
In other words, if you don't include the confirmation on your form, then this validation will be skipped. Now that's a good thing, because there may be some forms where we want it and we want to ensure that the two match and other times when we don't care, and we wanna leave it off the form, and not have the validation run. The default message that it uses for this doesn't match confirmation. The last one is a bit different from the other nine that we've looked at. Instead of checking the current model's data, it validates the data of associated models.

In other words, it uses the active record association like has many and belongs to, to make sure that those objects which are related to an object are also valid before it will consider this current object to be valid and let it be saved. You only need to use it when you're creating two or more objects in one step, and there's a real dependency between the two. Let's imagine that a user is going to create an auction for a car. The user fills out the auction details, such as the minimum bid, and the information about the car, the year, the model, the colour.
And they do it all on one form. When they submit the form, we're gonna save the auction to the auctions table, and it's gonna have has one related to the car in the cars table. We're gonna save the auction first. It passes all its validation. It saves to the database. Next, we save the car, but the user forgot to put in the colour, so it fails validations and can't save. But now we've got a problem. We already saved the record for the auction. We need to delete it so that we can then give the user the form back and let them try again.
It's much better if we can look ahead by using validates_associated and see that the car is going to be invalid before we save the auction.The two models are closely related so we need to consider one of them invalid whenever the other one is invalid. The first argument, in this case, is gonna be an association name, not an attribute. It's going to call valid on the object or the array of objects. In other words, it's gonna run all of its validations. Validates_associated does not fail if the object does not exist.

Therefore you should also use validates_presence_of if the object must exist. And last, of all, beware of infinite loops and long cascades.You wouldn't want to have your auction validate that the car is valid and then the car must also consider the auction to be valid. It would just keep looping back and forth, checking each one, and saying hey are you valid? Yes, I'm valid, but are you valid? And it would go back to the other one again. It would just keep looping. And the same thing is true for long cascades of objects.
You wouldn't want to have lots of things dependent on each other before you could allow things to start saving. Last, of all, I just wanna look at a couple of the global options that you can use. Most of these methods are going to accept options for allow_nil and allow_blank.Allow_nil will skip validations if it's nil, allow_blank allows it to skip if it's blank. All of them are going to allow you to pass in on, and then provide save, create, or update. So it's only gonna validate in those cases. If we have a new record and we're creating it, or if we're updating an existing record, that's update, or on save, it only runs the validation in both cases.

And that's the default, for it to run both times, whether we're creating or updating the record. You also can pass in if, and unless. And then you can give it a method, which is defined in the model. And that method should return true or false, so it will only run the validation if it calls that method and that method returns true or false. That gives you a good overview of the validations that Rails provide for us. 

Comments

Popular posts from this blog

How to solve migration issues with rails

ActiveRecords and ActiveRelation

CRUD Basics