Rails Validators - A Quick Guide and Cheatsheet
Published: 2022-04-12 15:39:18

In the complex world of Rails, what exactly are validations and how can we use them? In this blog, I will give an overview of Rails validators and list some common and useful examples. The [Rails Guides](https://guides.rubyonrails.org/active_record_validations.html) state that, "validations are used to ensure that only valid data is saved into your database." As a silly analogy, you can consider validations to be the backend's bouncer, making sure all data is dressed appropriately before entering club database. "Model-level validations are the best way to ensure that only valid data is saved into your database." Client-side validations are possible, but can be insecure or inefficient when used alone. Backend validations ensure that your database is only receiving safe and appropriate data. 

###What Triggers a Validation? 
Validations are implemented when any type of change is made to the database. You will run into this most often when you `.save` or `.create`, but you can also manually trigger a validation with `.valid?` or `.invalid?`. There is also a built in validation method `on:` that allows you to determine when the validation is triggered: 
```ruby
class User < ApplicationRecord
  validates :age, numericality: true, on: :update
end
``` 
###Common Built-in Validation Methods
Active Record has numerous built-in validation methods that can be employed for common validation needs. Every time these validations fail, they will trigger an error which you can decide to handle in your own way (more on that later). One of the most common built-in validators is `presence:` which checks that a certain value has been entered/exists. 
```ruby
class User < ApplicationRecord
  validates :username, presence: true
end
```
*Note that attributes can also be chained together if the same type of validation needs to be provided for each one: 
```ruby
class User < ApplicationRecord
  validates :username, :birthday, :full_name, presence: true
end
```
`presence:` is best used when you do not have any other validations in place. If you have another validation in place for the same attribute, `presence:` becomes implicit and is not required.

Another common built-in validation is `length:`, which checks various length constraints: 
 ```ruby
class User < ApplicationRecord
  validates :name, length: { minimum: 2 }
  validates :bio, length: { maximum: 500 }
  validates :password, length: { in: 6..20 }
  validates :drivers_license, length: { is: 9 }
end
```
The `length:` validator can be used against numerous different constraints such as maximum, minimum, an exact length, or a range. 

`numericality:` is used to validate an attribute's numeric value. 
```ruby
class User < ApplicationRecord
  validates :birthday, numericality: true
  validates :phone_number, numericality: { only_integer: true }
end
```
There are a multitude of `numericality:` constraints including: `:greater_than`, `:greater_than_or_equal_to`, `:equal_to`, `:less_than`, `:less_than_or_equal_to`, `:other_than`, `:in`(specifies range), `:odd`, `:even`. These validators can be used for a wide range of purposes and are intuitively named for ease of use.   

`inclusion:` is another helpful validator that can ensure that a certain value is included. This can be useful if a user is offered a list of options to choose from, and needs to be constrained to that list.  
```ruby
class User < ApplicationRecord
  validates :eye_color, inclusion: ["brown", "blue", "hazel", "green", "grey"]
end
```
Another very common validator is `uniqueness:`, this is important for ensure that data, such as usernames or emails are completely unique to a specific user. 
```ruby
class User < ApplicationRecord
  validates :username, uniqueness: true
end
```
Some interesting validations are `:allow_blank` and `:allow_nil`, these validations are used in a way that bypasses the built-in `presence: true` so that if information is entered it can be validated, but it can also be left blank or nil. 
```ruby
class User < ApplicationRecord
  validates :bio, length: { minimum: 250 }, allow_blank: true
end
```
You can also implement conditional validations that are only triggered if a certain condition is met. 
```ruby 
class Order < ApplicationRecord
  validates :card_number, presence: true, if: :paid_with_card?

  def paid_with_card?
    payment_type == "card"
  end
end
```
It is also possible to contain your validations within a certain scope.
```ruby
class Gate < ApplicationRecord
  validates :gate_num, uniqueness: { scope: :terminal }
end
```

###Custom Validations
Listed above are just a few of the many built in Active Record validation methods, however, when these aren't enough we also have the ability to build our own custom validations. The syntax is as follows: 
```ruby
class CustomValidator < ActiveModel::Validator
  def validate(record)
    unless record.species == 'dog' 
      record.errors.add :species, "Dogs only!"
    end
  end
end
```
A common syntax gotcha with custom validations is that custom validations use `validate` rather than `validates`. When you combine your own custom validations with the myriad of built-in methods, your validating possibilities are nearly endless!

###Error Handling
The way you want to handle the errors is a larger topic beyond the scope of this blog as Rails provides you with multiple options, however, I would like to highlight the built-in `message:` method as it is incorporated directly into your validations.
```ruby
class User < ApplicationRecord
  validates :username, presence: { message: "must be given please" }
end
```
###Conclusion
Rails validations are a simple and effective way to ensure you are allowing appropriate and safe data into your database. You can choose from numerous built-in validator methods for your most common validation needs or you can use your creative freedom and design custom validations for unique needs. 


###-Sources-
[Ruby on Rails Guides](https://guides.rubyonrails.org/active_record_validations.html)