Custom Validations

Posted by Gio Zavaglia on September 9, 2019

Whenever we create an account or log in into a website, we get errors if we don’t do what we’re supposed to do. For example, if we want to create an account in any website and we select a username that someone else has, the website will throw an error to us to let us know that it couldn’t creat the account because the username was taken. Or if we want to log in and we type the wrong password, we would also get an error telling us that we couldn’t log in because the password doesn’t match. So how does the app knows all these?

ActiveRecord has several solutions to help us validate usernames, passwords, to make sure that arguments meet the length requirement, or if something is left blank. The keyword is validates.

We can validate whatever we want! Like:

Class Author < ActiveRecord::Base
            validates :name, presence: true
			validates :phone_number, length: { minimum: 10 }
			validates :name, uniqueness: true
end
			

The first line validates that the name is not blank; the second line, takes care of making sure phone numbers have a minimum of 10 characters, to avoid any invalid data in our databases; the las line takes care of the uniqueness of our name, making sure we’re not taking any names that are used by other user.

Not only this, we can make our custom validations for anything we want. In the lab Rails/ActiveRecord Validations we’re tasked to create our own validator that tells the user if their title is not clickbait-y enough. To determine what is and isn’t clickbait-material, our app should take the title of a post and look if it contains either “Won’t Believe”, “Guess”, “Top #”, or “Secret”. If any of those words are missing from a title, an error should be dropped to let the user know. So how do we create a custom validation? I created a new helper class within the models folder called ClickbaitValidator which inherites from the ActiveRecord module EachValidator

class ClickbaitValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /(Won't Believe|Secret|Top \d|Guess)/
      record.errors[attribute] << ("Not a clickbait title")
    end
  end
end

inside, I overrite the #validate_each method: it provides acess to the individual attribute being validated as well as the entire record and values . In the Post model we need to provide a flag to expect the new validation class to get to work.

class Post < ActiveRecord::Base
  validates :title, presence: true
  validates :content, length: {minimum: 250}
  validates :summary, length: {maximum: 250}
  validates :category, inclusion: {in: %w(Fiction Non-Fiction)}
  validates :title, clickbait: true
end

The last line is what triggers the error if the title doesn’t contain the keywords that we told it too. This way, we can create validations for anything we’d like! Crazy right?