Ruby on Rails: Validation Errors
Tags: rails, programming, webdev, beginners
Published: 2022-04-06 16:27:27

## Validation
Validations are used in Rails to ensure the data saved to the database is valid. It helps prevent any issues further further down the road. Such as if a user were to fill out a form, it's important they fill it out with valid data- like confirming their phone number is 10 digits long. This will save a lot of debugging and headaches, preventing that issue to persist until it's used.

There are a couple ways to check if the object is valid. In rails, validations are run before _saving_ an active record object, and if there are errors then it will not save. If a user tries to input a phone number with 9 digits, the validation will recognize it is not valid and won't save the information in the data base, giving the user an error message.

We can use valid? or invalid? to check this.

```Ruby
class Person < ApplicationRecord
   validates :phone, presence: true, length:{ minimum, 10 }
end
```
We can open an irb/console session and test out the validity of our Person class, by saving a new instance method.

```
irb> Person.create(phone: 555-321-112).invalid?
=> true
irb> Person.create(phone: 555-321-112).valid?
=> false
irb> Person.create(phone: 555-321-1128).valid?
=> true

```
 
_valid?_ will trigger the validations and return true if no errors were found and false if there are errors. _invalid?_ is the opposite and will return true if there are errors and false if there aren't errors.

## Validation Errors
We can run our own validations while writing our code to check the validity as we work. After Active Record completes the validations, any errors that may arise can be looked at through errors instance methods, which will return the errors. In order for an object to be valid, the collection of errors must be empty after running the validation. We'll go through errors collection to help us do this.


## Errors Collection

**errors** : errors returns an instance of the class that contains the errors. It allows us to further look into the different details of the error, so we can attach other methods to the end of it. Some common methods to pair with errors is _.message_, ._full_messages_ (_to_a_ alias), and _.full_messages_for(:attribute)_

```
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.message
=> "is too short(minimum is 10 characters)"
irb> person.errors.full_messages
=> ["Phone is too short (minimum is 10 characters)"]
irb> person.errors.full_messages_for(:phone)
=> ["is too short (minimum is 10 characters)"]

irb> person = Person.new(phone: 555-643-2342)
irb> person.valid?
=> true
irb> person.errors.full_messages
=> []
```

**errors[]** : To verify a particular attribute of the object we can run _errors[:attribute]_. It will return an array of error message strings for that particular attribute, and if there are no errors it will return empty.

```
irb> person = Person.new(phone: 555-123-123)
irb> person.valid?
=> false
irb> person.errors[:phone]
=> ["is too short (minimum is 10 characters)"]

irb> person = Person.new(phone: 555-123-1234)
irb> person.valid?
=> true
irb> person.errors[:name]
=>[]

```

**errors.where** : returns an array of error objects. We use this compared to errors[] when we want more information than just the message. From the objects, you can then look further into it to get more information.

```
irb> person = Person.new
irb> person.valid?
=>false

irb> person.errors.where(:phone)
=>[...] #all errors for :phone attribute. Both presence and length errors

irb> person.errors.where(:phone, :too_short) 
=> [...] # :too_short errors for :phone attribute

irb> person.errors.where(:phone).first.attribute
=> :name
irb> person.errors.where(:phone).first.type
=> :too_short
irb> person.errors.where(:phone).first.options[:count]
=> 10

```

**errors.add** : creates the error object by taking an attribute, an error type and additional options hash. These are helpful if you are creating your own validators

```Ruby
class Person < ApplicationRecord
  validate do |person|
     errors.add :phone, :too_long, message: "has too many numbers"
  end
end
```
```
irb> person = Person.create
irb> person.errors.where(:phone).first.type
=> :too_long
irb> person.errors.where(:phone).first.full_message
=> "Phone has too many numbers

```

**errors[:base]** : can add errors to the objects state as a whole instead of being related to a specific attribute as with _errors.add_. Also good for when you are writing your own validations.

```Ruby
class Person < ApplicationRecord
  validate do |person|
    errors.add :base, :invalid, message: "This phone number is invalid because ..."
  end
end
```
```
irb> person = Person.create
irb> person.errors.where(:base).first.full_message
=> "This phone number is invalid because ..."

```

**errors.clear** : used when you intentionally want to clear the errors collection. It doesn't actually make the object valid though, the errors collection will be empty but next time you save or validate that method, the validations will run again. 

```
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.empty?
=> false
```
```
irb> person.errors.clear
irb> person.errors.empty?
=> true

```

**errors.size** : returns the total number of errors for the object.

```
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.size
=> 2 #phone does not exist, and is less than minimum length.

irb> person = Person.new(phone: 555-123-123)
irb> person.valid?
=> false
irb> person.errors.size
=> 1 # phone exists, but below minimum length.
```

## Errors in relation to custom methods
We can add errors to our collection when they are invalid. We can conditionally render out errors.

```Ruby
validate :phone_cannot_be_more_than_number

def phone_cannot_be_more_than_number
  if phone.present? && phone length > 11
  errors.add(:phone, "number is too long")
    
```
When added to custom methods, it will run every time you call valid? or save the object, unless we give it an :on option to validate the method with either :create or :update.



## Sources
https://guides.rubyonrails.org/active_record_validations.html#custom-methods

https://api.rubyonrails.org/v6.1.3/classes/ActiveModel/Errors.html#method-i-messages

https://guides.rubyonrails.org/active_record_validations.html#working-with-validation-errors