Implementing Data Validations in Rails 5
This guide walks through how to implement data validations in Rails 5, specifically it explains how to require data to be entered in order to create or edit records in the database.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

We're moving along the project quite nicely. In this section, we are going to cover data management. Open Pivotal Tracker and let’s move the tab for this sprint to the current section and double click to open the item and take a look at our tasks. We will be working to
- Implement validations
- Create Data relationships
- Create custom scopes
- Implement virtual attributes
- Setting data defaults
- Integrate concerns
- Nested attributes for blog tags

All these tasks are directly related to working with the model. Though we'll still be working with the full MVC architecture, our focus will be on the models specifically. Let's click the "Start" button for this sprint, and switch over to the terminal.

Creating a New Feature Branch

Navigate to your application. We are going to create a new branch, but before we do that, we have to switch back to our master branch using the imperative git checkout master. Remember we merged the pull request with all of our portfolio feature items on GitHub. So our local branch now needs to sync up with our remote branch. To do that we need to run a git pull.

This will bring in all the changes, and we're ready to move forward. Now we are ready to create our new branch.
git checkout -b data-feature.

Now that we are on our new branch, access the code base in sublime and close out all the open files. With this approach we can start fresh on our new topic.

Understanding the need for Data Validations

The first thing we will do is discover how to implement data validations. This may not have occurred to you, but in general, Rails is open to allow you to do whatever you want.

I'll show you an example. Go to your rails console rails c and create a blog with no attributes in it. You can use the simple imperative Blog.create(). Next use Blog.last. Notice we now have a blog object with an id of 17, however, because I did not pass in a body or a title when I created it, both of those values are nil. Also, it does not have a slug, which is a very bad thing because without it, there's no way it can be found in the browser. This will cause all kinds of errors.

large

One common detail you see with errors in Rails, is that when you have an attribute like a title with a nil value, or in this case a slug with no value, when you try to call a method on it, you'll get what's called a Nil error. Let's see this in action.

Start the rails server with rails s. Go to localhost:3000/blogs. Scroll all the way down to the bottom of the blogs list. You will see that you have an item, as there is a draft link, however there is no data associated with this blog. If you click on show, we have nothing. Without a slug, there can be no friendly id so the URL reverts back to a numeric value for the id, which in this case shows a 17.

Let's pretend we want to do make all of our titles uppercase. This is just temporary because we don't want it in the long run. Open your blog/index.html.erb file and add the method .upcase to your title, like this:

- <td><%= blog.title %></td>
+ <td><%= blog.title.upcase %></td>

If you save and refresh the browser, you'll get an error. This error indicates undefined method ‘upcase’ for nil:NilClass

large

This means that there is no value for the upcase method to run on. However, upcase executes for all of our other blog items. Let’s take a look at how that works. Go to the rails console rails c and delete the last record we just created which had the nil value. To do that use the imperative Blog.last.delete. Now, with that removed, if we restart the rails server and refresh the browser, you can see that the error message is gone. All of our other blogposts had titles. It was just that last blog item that was causing the error.

I actually forced this issue to show you the error, but there are many times when such errors would occur in real world development. A great example would be, that you have a user class which manages all the users. Originally the User has a username, password and an email address. But somewhere down the line, you want to add a first name and a last name to your User. You add that code and everything seems to work. You create some more functionality that calls for the first name to be displayed. Suddenly, you start getting some bugs that are NIL errors. It may be confusing at first, but soon you would discover the error occurred because the first few records that you created did not have a first name and a last name. It was the nil values causing an error.

Implementing Data Validations

You can protect your data and prevent these errors from occurring using something called data validation. Right now, we are able to create a blog that has no title or description. To fix this, go to blog.rb. This is your model file and is therefore found in the model directory. We will use validates_presence_of followed by the attributes we want to ensure will be included in our data. In this case that is :title and :body

class Blog < ApplicationRecord
  enum status: { draft: 0, published: 1 }
  extend FriendlyId
  friendly_id :title, use: :slugged

  validates_presence_of :title, :body
end

We are validating these attributes because I don't think there'll ever be a situation where we want to have a blog post without a title or a body. With this in place, a blog post must have a body and a title, or it will not be created.

To see this in action, switch back to the terminal and open the console. If you try to run the code Blog.create() without any parameters, it simply will not create a blog for you. You will see the response BEGIN and then ROLLBACK which means it did not work.

large

To see the actual error, use the imperative Blog.create!(). The error indicates ActiveRecord::RecordInvalid: Validation failed: Title can’t be blank, Body can’t be blank

large

So our data validation is working!

Start the rails server and head to localhost:3000/blogs in the browser . Click on the New Blog button. If you hit the Create Blog button without giving any data, you will get this error message: 2 errors prohibited this blog from being saved: Title can’t be blank Body can’t be blank

If you type in a title and a body and then hit Create Blog, you will discover that the data validations are working correctly!

The super efficient piece of this, is that the validation works for the other parts of the CRUD functionality as well. For example, if I try to edit a record, and leave the body blank, then hit the "Update blog" button, the system doesn't complete the process, but returns with an error notice: Body can’t be blank.

This is such a great way of implementing validations, as it prevents bugs. Anytime anyone has to touch the database, the validations will kick in.

Setting Other Validations

Let's create the validations for the other items in our app. Openportfolio.rb and skill.rb. Also, open schema.rb so we can pick and choose which attributes should be validated.

For portfolios, we should have a title. I do not think it is necessary to force a subtitle, rather, we should leave that as optional. We do however want a body, a main image and a thumb image. We wouldn’t want to have a portfolio item without images associated with them. (You can decide if images are important to you, but for the vision I have for this app I think it is a good idea).

Accordingly, inside our class we want to use validates_presence_of and then add our attributes.

class Portfolio < ApplicationRecord
  validates_presence_of :title, :body, :main_image, :thumb_image
end

Next, for skills, we want to validate the presence of title and percent utilized. So, let's add those in. Just a reminder, if other files are open, such as schema.rb, sublime will auto-complete methods and attributes for us, and this is how I was able to create the validations so quickly.

class Skill < ApplicationRecord
  validates_presence_of :title, :percent_utilized
end

Make sure to save your files! With that done, we should be good to push our files to our GitHub.

Run a git status and you will see all the files that we have modified and are staged for commit. Next use git add . After that, employ git commit -m ‘Implemented validations for blogs skills and portfolio items.’. Last run git push origin data-feature. All the changes will be pushed up. Finally, we can go to our project management program and check the first task as complete.

In the next guide we will explore how we can create data relationsips.