Introducing Validations
Tags: rails, beginners, webdev, codenewbie
Published: 2023-01-21 20:52:29

Active Record validations allow you control data saved to your database and help prevent headaches down the road!  From a properly formatted date... to making sure a username is unique upon signup, Active Record provides pre-defined helpers you can use to make sure the input meets requirements. Let's take a look at some common validations that help keep your database tables cohesive.


![diagram showing validations to database](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hl3778gtxwrpkawlylw.png)

There are a few ways you can provide validations for data but the most efficient way is by using them server side at the model level.  Model level validations are database agnostic (compatible with any database), cannot be bypassed by the end users, and are easy to test and maintain. Now that being said, there are benefits to having both server side and client side validation! It can improve application performance by not having to process invalid data. To get the grasp of the differences and benefits of using both, check out this [article](https://www.packetlabs.net/posts/input-validation/). 

So where in the process do validations take place?  Active Record validations allow us to validate data **before** being stored in our database. They are triggered when using the `create`, `save` and `update` methods. The validations run right before the SQL commands are sent to the database, so if any fail, Active Record will not perform the SQL INSERT or UPDATE. If the record is invalid, `create` returns the object, `save` and `update` return false, and all the bang versions of these methods raise an exception. (e.g. `create!`) Here is a list of methods that [**skip** validations.](https://guides.rubyonrails.org/active_record_validations.html#skipping-validations) 

</br>
![presence and absence validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cedkv1pmzheorudmfwtw.png)The `presence` helper makes sure that the specified attribute(s) are not empty. A `nil` or a blank string value will be invalid. 
```ruby
class Student < ApplicationRecord
  validates :name, :grade, presence: true
end
```
In the example above, Active Record will not create a new student without a name and grade. The direct opposite helper is `absence`, which will make sure the attribute(s) are nil or a blank string. 

</br>
![uniqueness validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ol1cesmvzeb7d8o2gsp.png)It's common to need a unique attribute value, for example, you would probably want unique usernames for your application. Here the helper will search the Student table for existing records to determine the uniqueness of the specified attribute. 

```ruby
class Student < ApplicationRecord
  validates :username, uniqueness: true
end
```
There is a `scope` option available with `uniqueness` that allows you to specify additional columns to consider when checking for uniqueness. 
```ruby
class Assignment < ApplicationRecord
  belongs_to :student
  validates :title, presence: true, uniqueness: { scope: :student_id }
end
```
This is requiring that the combination of the assignment `title` and `student_id` be unique. Other student accounts can have the same assignment `title`, but it will not be duplicated in any student account. 

</br>
![length validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hke9xcan1pi6hyhzc76c.png) There are many options for validating the length of an attribute's value... 

```ruby
class Student < ApplicationRecord
  validates :name, length: { minimum: 5 } # sets minimum
  validates :bio, length: { maximum: 500 } # sets maximum
  validates :password, length: { in: 5..12 } # provides a range
  validates :library_number, length: { is: 8 } # must match length
end
```
You can customize error messages using default error messages `:wrong_length`, `:too_long`, and `:too_short`. Note that the default messages are plural(e.g. 'characters').  There is also `%{count}` which is a placeholder for the number constraint being used. 
```ruby
class Student < ApplicationRecord
  validates :bio, length: { maximum: 500,
    too_long: "%{count} characters is the maximum allowed" }
  # sets maximum, custom message specifying the character limit
end
```
</br>
![format validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86gr0ofwgepgqnge05iw.png)You might need to `format` strings for your application, in which case, you can test if they match specifications given  using the `:with` option. This can come in handy to check that a valid email address is entered or if you wanted to exclude numbers/symbols. 

```ruby
class Student < ApplicationRecord
  validates :name, format: { with: /\A[a-zA-Z]+\z/,
    message: "only allows letters" }
end
```

</br>
![numericality validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ls5xjphvzwt8m95tv6l0.png) This helper ensures attributes have only numeric values. To specify **only integer numbers**, use `:only_integer` set to true. The `numericality` helper does not allow `nil` values. To allow for this option you can use `allow_nil: true`.

```ruby
class Test < ApplicationRecord
  validates :score, numericality: { only_integer: true }
end
```

`:greater_than`
`:greater_than_or_equal_to`
`:equal_to`
`:less_than`
`:less_than_or_equal_to`
`:other_than` (value must be other than the supplied value)
`:in` (value must be in the supplied range)
`:odd`
`:even`


</br>
![comparison validation helper header](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvetk3nxtl4jt0oldsvv.png) This helper compares two values and will validate only if the comparison is true. Below the validation requires the race `:start_time` to be `:less_than` the `:finish_time` or it will be invalid. 

```ruby
class Race < ApplicationRecord
  validates :start_time, comparison: { less_than: :finish_time }
end
```
These are the supported options for comparison:
`:greater_than `
`:greater_than_or_equal_to `
`:equal_to `
`:less_than`
`:less_than_or_equal_to`
`:other_than` (value must be other than the supplied value) 

---
Before I wrap up, I wanted to demonstrate some of the many ways you can check your validations using the `rails console`:

```ruby
class User < ApplicationRecord
  validates :username, presence: true
end
```

```
$ rails console

>> user1 = User.create(username: "")
=> #<User id: nil username: nil, created_at: nil, updated_at: nil>
#create returns the object with no id assigned, meaning it did not save to the database

>> user1.save
=> false

>> user2 = User.create!(username: "")
=> ActiveRecord::RecordInvalid (Validation failed: Username can't be blank)
#using the bang operator with create raises an exception when invalid
 
>>user3 = User.create(username: "Thor").valid?
=> true

>>user1.valid?
=> false
#you can use the opposite .invalid? 

>>user1.errors.any?
=> true
>>user1.errors.full_messages
=>  ["Username can't be blank"] 
```
I only scratched the surface on what's possible using Active Record validations! [Explore more](https://guides.rubyonrails.org/active_record_validations.html) pre-built helpers, conditional and custom validations, and validation errors. 

![database with text so fresh and so clean clean](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kgwmrdxrsqtn94f2m391.png)
---

**You can connect with me on** [LinkedIn](https://www.linkedin.com/in/rachelsmithstark/) **&** [GitHub](https://github.com/rstarksmith)

Resources: [Rails Guides - Active Record Validations] (https://guides.rubyonrails.org/active_record_validations.html)