Ruby on Rails: Validation Errors

opomeroy26

Olivia Pomeroy

Posted on April 6, 2022

Ruby on Rails: Validation Errors

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.

class Person < ApplicationRecord
   validates :phone, presence: true, length:{ minimum, 10 }
end
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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
=> []
Enter fullscreen mode Exit fullscreen mode

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]
=>[]

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

class Person < ApplicationRecord
  validate do |person|
     errors.add :phone, :too_long, message: "has too many numbers"
  end
end
Enter fullscreen mode Exit fullscreen mode
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

Enter fullscreen mode Exit fullscreen mode

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.

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
irb> person.errors.clear
irb> person.errors.empty?
=> true

Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Errors in relation to custom methods

We can add errors to our collection when they are invalid. We can conditionally render out errors.

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")

Enter fullscreen mode Exit fullscreen mode

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

💖 💪 🙅 🚩
opomeroy26
Olivia Pomeroy

Posted on April 6, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related