Join Kevin Skoglund for an in-depth discussion in this video Using validation methods, part of Ruby on Rails 4 Essential Training.
In the last movie, we took a look at the ten validation methods that are available to us in Ruby on Rails. In this movie, we're going to work on adding those to our simple CMS application. I'm going to walk you through the steps and actually tell you what validations to add, but when you're on your own with an application, you're probably going to want to first ask yourself what to validate. You need to figure that, before you just start writing validations. You need to ask yourself, what are your data concerns? And you need to decide, what does good data look like? What does bad data look like? Is it, for example, acceptable to have a city entered into your database, that's in all lower case? If you're storing a social security number, is it okay for it to have dashes or spaces in it? Then you should take a look at what restrictions does your database schema impose? What field types are using? Do you need to make sure that something is a number? What are the field links? Do we need to make sure that something is less than certain length so that it will fit in the database field that we've allowed for it? And is null an allowed value for a field? We want to make sure that our application model can act as the enforcer on our databases behalf.
We want to catch the problems in our applications so that we can handle them in our application rather than have the database give us a problem. And what would stop your application from working? Even something very simple like page.name.upcase. Well if it turns out that name is not an empty string but is actually nill well then upcase would return an error to us. Typically things you don't need to worry about validating are IDs on tables, the foreign keys, and the timestamps. These are really the utilities that are built into relational databases and to Rails, making things nice for you.
They're not really the data that you need to worry about. They're more utilitarian in their purpose. Let's go to our application and start using validations. Let's start by going into our models, and we're going to go to our subject model, and right where we have our validates presence of name, I'm just going to replace that with a large block that I'm going to paste in. And it includes some notes here, just to help remind you what we're doing, validates presence of name, followed by validates length of name, making sure that the maximum length is 255. Now it validates presence of and validates length of are compatible but they don't do exactly the same thing.
We could do validates length of minimum one if we wanted but that's a little different then validates presence of making sure there that there is something. Because first of all we would get different error messages. The first one, presents of, would say that it can't be blank. And the second one would say that it's too short. We would have two different error messages. But more importantly, validates length of doesn't care about spaces. A space is considered a character. And so validates length of would allow us to have 255 spaces. That's probably not what we want, if we're trying to validate that there is a name present.
Let's save our subject model, and let's go over to our page model. And, right below the relationships but before the scopes, I'm just going to paste in some more validations. I got validates presence of name. Valadates length of name. As you just saw, were going to have those as companions. The order is important. The fact that the value presence of, comes first Means that, that'll be the error that it's returned on name, before it ever gets to the other ones. And then validates presence of and length of the permalink. To make sure that we have a permalink submitted. Then I'm also going to validate the uniqueness of that permalink.
Right this permalink is the way we're going to locate each of these pages. It has to be unique, otherwise how would we know which page the users looking for. So permalink has to be unique. That means it's going to issue a call to the database in order to check and see if this permalink has already been submitted to the database. If we wanted it so that the page name could be repeated, let's say maybe there was a page called resources and if the subject was under press, then press resources would be valid, but if it was under student then student resources would also be valid, right? We could have it two different times.
To do that you would scope it and you would say scope this by the ID so make sure that they're not unique by ID. Because when I go back and search for' em later I'm going to include that subject. I'm going to factor that in, to looking for these later so it's okay. Next let's go over to Section. And let's paste in some validations here. I'm going to start with having a constant, that will tell what the different content types that the section is allowed to have. It's allowed to have text and it's allowed to have html. So, I'm going to have my validates presence of name, and length of name like we had before, but I'm also going to use validates inclusion of, to make sure that the content type is in either text or html.
And I'm actually going to just use content types here, there we go, so that will use content types to make sure that's in there. And the message would be, that it has to be in one of the content types, and I'm just joining those together with a comma. And then last of all, validate presence of content. Right a, a sections no good if we don't actually have content to display to the user, so we're going to make sure that they've given us some kind of content. And because we're using a MySQL text field for that, it doesn't have a character limit, whereas the name field can only be 255 characters.
Let's save that. I also see that I forgot to save page. Make sure that all those are saved and then we'll go to Admin User and right after the relationships here, I'm going to paste in some validations for the user. So we're going to make sure that the user has a first name and they have last name. I've got a maximum of 25 and 50 on those. Check their username to make sure it's present, make sure it's the right length, and then, make sure that it's unique. Right? Three things I'm doing on user name. Make sure it's there, make sure it's the right length, make sure it's unique. On email, make sure the presence is there, make sure that the length is good. I've limited it to 100.
And then, I'm using validates format of with EMAIL_REGEX. And EMAIL_REGEX I've got defined up here and that regular expression will then be run to find out if this email is in the right format. There are a number of different regular expressions you can use for validating emails, this is a relatively simple one. And then last of all I've got validates confirmation of email, now remember that's going to add a virtual attribute I don't have a column for that on my table its going to add a virtual attribute called email_confirmation and then if that value is there.
It'll make sure that it matches my email, so if I ever on a form, say hey, I'd like them to, to re-enter this email address, then if it's there, it'll be checked. If it's not there, I take it off the form, it'll stop being checked, and it won't run this validation anymore. So now that we have validations installed for all four of these, let's actually try them out. Let's go to our command line, this is a great way to try your validations from the root of your Rails application. Run rails console and once that opens up, let's try creating a new subject. So I'm just going to say s equals subjects.new.
Okay, so now we've got a subject. If I do s.errors. We'll take a look at the errors hash that it returns. So here's the error hash. And you can see that there are no errors at the moment. Now, when we save or update an object, Rails first ask if this object is valid before it proceeds with the save or the update. And it does that by calling a method that all active record objects have. Which is called valid, with a question mark after it. And we can use valid to run validations without saving. At any point if you want to check and find out if something's valid, you just call valid question mark on it.
So is it valid? False, it's not valid, it doesn't meet the requirements. Now if we check the errors, after running valid, you can see that we have an error here, messages. Name, can't be blank. If we do s.errors.full_messages as we already saw before, it'll return to us a nice English string that'll tell us that name can't be blank. So let's give it a name s.name equals test And let's say s.errors. Now, our error is still there, right? It doesn't clear it until we either tell it to clear it with s.errors.clear.
Or, if you run valid again, then it will clear the errors. And then reevaluate whether it's valid or not. So that's typically the way you would do it. You would just say, all right, check again whether it's valid. Now that I've given it a name, check again whether it's valid. So now it's true. If I check the errors again. You'll see that there are no errors there. One of my other validations was for length. So let's just say s name equals and let's change it to x times 300. So that'll give me a, a name that's 300 x's long. And let's ask now.
Is that valid? It comes back and says no, it's not valid. If we take a look at the errors. We'll see that it says that the name is too long. The maximum is 255 characters. Now, we're not saving this to the database, we're just simply instantiating this object and then running valid on it. If we wanted to, then the next step would be that we could save it to the database, once it's a valid object, object. Let's try a few more examples. I'm going to do this one with an admin user. So u equals admin user new. And then I'm going to provide a first name, and a last name, and a user name for John Doe.
So let's hit Return. We've got our user, u.valid. No, it's not valid. Notice that it did make a database call here to find out whether or not it was unique. That's what it's checking to see is whether it had one or not. But let's take a look at the errors, u.errors.full_messages. The username is too short. The minimum is eight characters, and the email can't be blank. And the email is invalid, so those are several problems that I have there. Let's try using a longer username, so u.username, and I'm going to enter on purpose kskoglund Which is the user that I created earlier.
That's a user that's already in my database. You can remind yourself of that if you do admin user all, you can see that I already have that user name here in the database. So now I have a new user ready to be saved that has the same username. And if I check u.valid, you can see that it comes back and it says false. u.errors.full_messages. And it says username has already been taken. Right, so you could see it make that database query, it finds out that that username has already been taken, it's not unique and so it doesn't pass validations. So let's try another one.
Let's go back. I'll just go up. And username now, we're going to make equal to johndoe123. That should be long enough to pass validations. So let's try adjusting the email. That's the, said that there was no email, so let's put in an email And let's just put in nowhere.com for our email. Is it valid? No, it says it's false. Let's go back and look at those error messages. The email is invalid. It's sent not in the right format. Right, that's not a valid email address. So, instead, we would need to change it.
Let's make it, instead, be firstname.lastname@example.org and now is it valid? It is valid if we take a look at the errors, there are none. Last of all let's take a look at that email confirmation. We've set a value for email, now let's also set a value for email_confirmation that's that virtual attribute and we're going to set this one to be something different so that it does not match. email@example.com. Now they don't match. So, if I say, u.valid? It comes up and says, false.
Why not? Let's look at the full messages. E-mail confirmation, doesn't match e-mail. Now notice the first time it was still valid because we did not include a confirmation. It only checks if the confirmation is present, then it must match. But if it's not present, it's still considered valid. Validations are an important part of every Rails application, because you need to make sure that the data that comes into your application is the data that you're expecting to come in. And that it looks and works the way that you expect it to work. So that your application can work the way that you expect.
- Why use Ruby on Rails?
- Installing Ruby on Rails on Mac and Windows
- Rendering templates and redirecting requests
- Generating and running database migrations
- Creating, updating, and deleting records
- Understanding association types
- Using layouts, partials, and view helpers
- Incorporating assets using asset pipeline
- Validating form data
- Authenticating users and managing user access
- Architecting RESTful applications
- Debugging and error handing