The very basics of Active Record Validations
Tags: ruby, rails, activerecord, crud
Published: 2022-06-22 19:38:52

Active Record Validations are a feature of Active Record that gives us the ability to validate data, before it reaches our database. This has a few benefits, but most importantly, we can make sure our database doesn't have unwanted values that could break our application later on.

This guide will attempt to explain how Active Record Validations work, using the Active Records Validations guide as a general reference.

---

## Why use validations?

First of all, why should we use validations? As alluded to before, validations are vital for making sure that all the values in our database are exactly within our expectations.

According to the Ruby on Rails guide:

> Model-level validations are the best way to ensure that only valid data is saved into your database. They are database agnostic, cannot be bypassed by end users, and are convenient to test and maintain.

For example, if our database has a column for phone numbers, we know (within reason) that there every number should by 10 digits long (including area code) and by made up of only digits (0-9). So, before creating a new phone number in our database, we should _validate_ it first. If it's invalid, we should reject it.

By making sure our database is valid, we can prevent potential bugs down the line.

---

## Validation Helpers

Validation helpers are the meat of Active Record Validations. These are pre-defined helpers that provide a set of built-in validation rules. We define our validations directly in the model class. With just the built-in validation helpers, we should be able to handle most, if not all, of our necessary validations.

Some of the most useful helpers include: presence, uniqueness, length, comparison, and format. The full list of built-in validation helpers can be found [**here**](https://guides.rubyonrails.org/active_record_validations.html#validation-helpers).

### _presence_

Presence validates that the specified attribute(s) are not empty (nil or an empty string: ""). It is, by far, the simplest helper, as well as, one of the most common helpers.

```ruby
  class Person < ApplicationRecord
    validates :name, :phone_number presence: true
  end
```

Now, Active Record won't allow us to create a new person unless there is a name and phone number present. Notice, by the way, that we define our validations directly in each model.

Alternatively, the helper _absence_ does the opposite, ensuring that one or more attributes are absent before saving a new record.

### _uniqueness_

This helper ensures that each value of one or more attributes are unique. One of the most obvious use cases for this would be to ensure every created user had a unique email address.

```ruby
  class User < ApplicationRecord
    validates :email uniqueness: true
  end
```

### _length_

This helper is exactly what you think is; it validates the length of the attribute value. There are a few different options available with _length_, to be as precise as you'd need to be. They are: _minimum_, _maximum_, _in_ (or _within_), and _is_.

```ruby
  class Customer < ApplicationRecord
    validates :phone_number length: {is: 10}
  end
```

For more info about the other options, visit the Ruby on Rails guide, [here](https://guides.rubyonrails.org/active_record_validations.html#length)

### _comparison_

_Comparison_ compares two values and will only validate if the comparison is true. Like _length_, _comparison_ has several options to choose from. They are: :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to, :equal_to, and :other_than.

```ruby
  class Employee < ApplicationRecord
    validates :hourly_wage comparison: {greater_than_or_equal_to: :minimum_wage}
  end
```

This examples validates that each employee's wage is never below minimum wage.

### _format_

The last validation helper in this blog is _format_. Simply put, it validates that a attribute value matches a pre-defined regex pattern. This is useful for making sure an email address or a password follows a specific format.

```ruby
  class User < ApplicationRecord
    validates :email format: {with: /^\w{2}\w*@\w+\.\w+$/}
  end
```

_format_ basically allows you to be as flexible with your validations as regular expressions are. The only drawback is having to use regular expressions...

---

## Conditional Validation

To make our validations even more dynamic, Active Record gives us the option to run our validations based on specific conditions that we can define. To add conditions to your validations, simply tag on an `:if` or an `:unless`, with the name of a function that evaluates to true or false, in symbol format. I like the example code for custom validations in the Rails [docs](https://guides.rubyonrails.org/active_record_validations.html#using-a-symbol-with-if-and-unless):

```ruby
  class Order < ApplicationRecord
    validates :card_number, presence: true, if: :paid_with_card?

    def paid_with_card?
      payment_type == "card"
    end
  end
```

In the example above, each payment has a "payment_type" associated with it. When using a credit card, we need to use the credit card number to process the payment. It would be wise to validate the credit card number before doing so, to ensure that only cc numbers in a specific format get processed, or else, the payment could fail and that is not ideal.

Adding conditions to our validations greatly enhances our ability to write complex validations in a easy to read manner. With what we now have, we can setup just about any validation we can think of with the Rails built-in validation helpers. But, as an alternative to using the built-in helpers, we can define our own validation methods that will even do the few things the built-in helpers cannot.

---

## Custom Validations

Although the built-in validation helpers that Active Record gives us are awesome, we don't have to use them at all, and, in fact, won't always be enough for the type of validation we need. Instead, we can define our own custom validations to do any sort of validating we could possible desire. Custom validations are generally used for more complex validations while the built-in helpers are efficient for using more straight-forward validations, as their name's imply.

Here's an example of a custom validator that fails if it's not the first of the month:

```ruby
  class DeliveryOrder < ApplicationRecord
    validate :promise_time_cannot_be_in_the_past

    def promise_time_cannot_be_in_the_past
      errors.add(:promise_time, "cannot be in the past") if self.promise_time < Date.today
    end
  end
```

The example above is for a delivery order at a restaurant or whatever. There's no way the we could possibly promise to deliver anything that is before the order was placed. This validation ensures we won't have to deal with this later down the line.

This could be written using the built-in validation helpers, but, for whatever reason, I decided I liked this better. Without having to understand the logic behind the validation, it's still obvious that this model is validating that the promise time cannot be in the past, as the name of the validation method eludes to. I guess it's up to preference for which way you'd like to use.

---

## Conclusion

In the article, I've only covered the absolute basics of Active Record Validations. The most glaring area I omitted was error handling. If you'd like to know more (and I encourage you to do so), please check out the main page on validations for Active Record [here](https://guides.rubyonrails.org/active_record_validations.html). The other bigger topic I didn't cover were the "Common Validation Options". They add a few additional ways to make your validations even more dynamic.

Just like everything else in Rails, once your comfortable writing validations and don't need to flip back to the docs regularly, you can write very easy validations in only a few lines of code that are basically human readable. It's pretty incredible.

---

## Resources & Acknowledgements

This article basically cherry-picks and summarizes parts of the guide on Active Record Validations from the Ruby on Rails guides and can be found [here](https://guides.rubyonrails.org/active_record_validations.html).

Besides the Rails guides, these two YouTube tutorials were extremely helpful in understanding how validation worked in Rails:

- [Ruby On Rails: Model Validations - Apple Juice Training](https://www.youtube.com/watch?v=SaCGlchTxLI&t=173s)
- [Rails for Beginners Part 12: Validations - GoRails](https://www.youtube.com/watch?v=l-Jv5vMjB70&t=39s)

That's it. Thanks for reading. Go Twins!