Model Validations

When you submit a Tweet on Twitter, it has a default limit of 140 characters. But how do they check it? What if I submit a Tweet with 141 characters? How does the system catch this and reject my Tweet?

This is where Model Validations come in. Effectively, your backend API can validate any data going into your database.

Here is a list of the most common validations used:

Helper Name Description
length validates the length of the attributes' values
presence validates that the specified attributes are present
absence validates that the specified attributes are absent
uniqueness validates that the attribute's value is unique right before the object gets saved
allow_blank will let validation pass if the attribute's value is blank?

The best way to approach this is to show you an example of how model validations are used:

class Post < ActiveRecord::Base
  validates :title, :length => { maximum: 140 }, :presence => true
  validates :content, :length => { maximum: 140 }, :allow_blank => true

  validate :spam_free
  validate :post_count

  private

  def post_count
    count = Post.count
    if count > 20
      self.errors.add(:base, "Cannot posts more than 20 posts")
    end
  end

  def spam_free
    # order all the posts reverse chronologically
    # get the posted time for the latest post
    last_post = Post.order(:created_at).last

    # goal: the user can only post after 1 minute
    if Post.any? and last_post.created_at > 1.minute.ago
      # if this is true, the last post was made in less 1 minute ago, so please raise an error
      self.errors.add(:base, "Cannot post within 1 minute")
    end
  end
end

Let's example line by line.

validates :title, :length => { maximum: 140 }, :presence => true
  • title attribute can have a maximum 140 characters; title attribute must be present in new record
  • record will not be saved if the title attribute is missing or exceed 140 characters
validates :content, :length => { maximum: 140 }, :allow_blank => true
  • content attribute can have a maximum 140 characters but can be left blank

We use the validates helper for attributes that are already defined in the database. We can call these default validators by Rails.

Now, what if we want to write custom validators? Well, in this case, we will use the validate method followed by the name of the custom method.

validate :spam_free
  • In this case, spam_free is a custom method, so we need to examine what's defined in the spam_free method.
  def spam_free
    # order all the posts reverse chronologically
    # get the posted time for the latest post
    last_post = Post.order(:created_at).last

    # goal: the user can only post after 1 minute
    if Post.any? and last_post.created_at > 1.minute.ago
      # if this is true, the last post was made in less 1 minute ago, so please raise an error
      self.errors.add(:base, "Cannot post within 1 minute")
    end
  end
  • We found the latest post (ordered by created_at time)
  • We make sure the latest post was made at least one minute ago
  • This way, we are rate limiting the frequency of new posts to 1 minute per new post
  • If the latest post was made less than 1 minute ago, the API will not create a new record

Likewise, let's examine the post_count method for custom validations.

  def post_count
    count = Post.count
    if count > 20
      self.errors.add(:base, "Cannot posts more than 20 posts")
    end
  end
  • We make sure there can only be 20 posts existing by counting the number of records of Post
  • Obviously, this validator is unreasonable in a real product

So, when do we use default validators vs custom validators? When your validation logic is complex and requires a custom method to work, then you should use custom validators. Otherwise, default validators will often satisfy your needs.

There's a huge documentation on all model validations by Rails.

Reference:

results matching ""

    No results matching ""