Creating Bulletproof Validations in Ruby on Rails with Custom Validators [Part II]
Strong foundations
Greeting
Hey guys, how've you been? It's AC, Alexandre Calaça here. I'm so excited that you landed here. Hope you enjoy this new article.
By the way, I would be glad to receive your feedback about it.
Since you're already here, consider follow me on github and here on Hashnode.
You might be interested in checking my complete articles list in here.
Objective
This is the Part II of the article Creating Bulletproof Validations in Ruby on Rails with Custom Validators.
Part I provided a basic introduction to validations.
In this article, we will provide a solid theory to validations in Ruby on Rails, with a focus on custom validations in separate classes with Ruby on Rails.
We will cover the basic concepts of validations, custom validators, Rails' approach to validations and their advantages and disadvantages.
By the end of this article, you will have a solid understanding of how custom validators work in Rails and how they can benefit your application development process.
Planning of this series:
Part I - Basic introduction
Part II - Strong Foundations (This article)
Part III - Implementation
Introduction
Ruby on Rails is a powerful web development framework that allows developers to rapidly build robust and scalable applications. One of the key features of Rails is its built-in support for validations, which allow developers to ensure that the data entered into their applications meets certain criteria. Validations are a critical part of any web application, as they help to ensure data integrity, prevent user errors, and improve the overall user experience.
In this article, we will explore the various types of validations available in Ruby on Rails, including built-in validations and custom validations. We will discuss how to use these validations to validate different types of data, including text, numbers, dates, and more. We will also cover common validation scenarios, such as validating the presence of data, validating the uniqueness of data, and validating the format of data.
Validations
IIn programming, validations are a set of rules or conditions that are applied to input data to ensure that it meets certain criteria. The purpose of validations is to ensure that the data entered by users or generated by the system is accurate, consistent, and safe to use.
Check Creating Bulletproof Validations in Ruby on Rails with Custom Validators [Part I ] for more details.
Validations in Ruby on Rails
In Ruby on Rails, validations are used to ensure that the data entered by users is valid and meets certain criteria before it is saved to the database. This helps to maintain data integrity and prevent errors in your application.
There are basically 3 approaches to validations:
- built-in validation methods
- Custom methods
- Custom validators
built-in validation methods
We already talked about this topic in the article Creating Bulletproof Validations in Ruby on Rails with Custom Validators [Part I ](blog.alexandrecalaca.com/creating-bulletpro..), but it seems worth it to refresh your memory.
Rails' current approach to validations is to define them directly in the model classes using Rails' built-in validation methods, such as validates_presence_of, validates_length_of, validates_format_of, etc. This approach works well for simple validations, but can become difficult to manage and maintain as the application grows and the number and complexity of validations increase.
Advantages
Besides other reasons, let's point out some:
Organizational clarity
Rails models are the standard way of organizing database tables and their associated business logic, including validations. By keeping all the validations for a given model in one place, it is easier to understand and maintain the code.
Ease of use
Rails provides a set of built-in validation helpers that make it easy to add common validations to your models, such as presence, length, format, and uniqueness. By using these helpers, you can write less code and ensure that your validations are consistent across your application.
Disadvantages
Let's point out some disadvantages.
Increased model complexity
As your application grows and more validations are added to your models, the size and complexity of your models can increase significantly. This can make it harder to understand and maintain your code, particularly if your models are responsible for a lot of different business logic.
Tight coupling
By storing validations in models, you may be creating a tight coupling between your business logic and your persistence layer. This can make it harder to change one without affecting the other, particularly if you have complex validation logic that depends on the state of your database.
Lack of reusability
If you have similar validation logic across multiple models, you may find yourself duplicating code across those models. This can lead to code duplication and a lack of reusability, which can make your code harder to maintain and more error-prone.
Custom methods
It's possible to create custom methods that verify the state of your models and add errors to the errors collection when they are invalid.
These methods can be used to implement validation rules that are not covered by the built-in validation methods or to encapsulate complex validation logic into a separate method.
To use a custom validation method in your model, you need to register it by using the validate class method, passing in the symbol for the validation method's name as an argument.
Let's check the following piece of code:
class MyModel < ApplicationRecord
validate :validate_my_rule
def validate_my_rule
# custom validation logic here
if some_condition_is_not_met
errors.add(:base, "Validation failed because...")
end
end
end
As you can see, we defined our custom method as validate_my_rule
. This line errors.add(:base, "Validation failed because...")
is responsible to add errors to the errors collection in case the previous criteria is invalid.
The following code is another example of a custom method.
class Invoice < ApplicationRecord
validate :expiration_date_cannot_be_in_the_past
def expiration_date_cannot_be_in_the_past
if expiration_date.present? && expiration_date < Date.today
errors.add(:expiration_date, "can't be in the past")
end
end
end
Advantages of custom methods
Let's point out two benefits:
Separation of Concerns By separating validation logic into its own class, you can keep your models focused on their primary responsibilities, which is to manage data storage and retrieval. This can help keep your models easy to read and maintain.
Flexibility Custom methods allow you to implement more complex validation rules that are not possible with the built-in validation methods. This can help you enforce business rules or constraints that are specific to your application.
Disadvantages of custom methods
While there are many advantages to using custom methods for validation in Ruby on Rails, there are also some potential disadvantages to consider:
Lack of Standardization Because custom validators methods are specific to your application, there is no standardization around how they should be implemented or named. This can make it more difficult for developers to understand and work with your codebase, especially if they are new to your project.
Increased Complexity While custom validators can help you enforce complex business rules or constraints, they can also increase the complexity of your codebase. This can make it more difficult to understand and maintain, especially if you have many custom validators that interact with each other.
Custom validators
As it already mentioned, Rails' current approach to validations is to define them directly in the model classes using Rails' built-in validation methods.
When the built-in validation helpers are not enough for our needs, you can write your own validators or validation methods as you prefer.
This article is mainly focused on the power of Custom validators in Ruby on Rails, which are reusable classes that define custom validation rules for your models. They allow you to encapsulate complex validation logic into a separate class, making your code easier to understand and maintain.
To create a custom validator in Rails, you need to define a class that inherits from ActiveModel::Validator and implements a validate method. The validate method should take a single argument, which is the model instance being validated, and add error messages to the model's errors collection if the validation fails.
Advantages
Custom validators in Rails provide a powerful and flexible way to define complex validation rules that are specific to your application's needs, while keeping your code clean and easy to maintain.
Anyway, let's point out two other reasons:
Code Reusability Custom validators can be reused across multiple models in your application, reducing code duplication and promoting code reusability. This can save time and effort when implementing similar validation logic in multiple models.
Encapsulation Custom validators allow you to encapsulate complex validation logic into a separate class, making your code easier to read, understand, and maintain. This can help to reduce complexity and make your codebase more organized.
Disadvantages
While custom validators in Ruby on Rails have several advantages, they also have a few potential disadvantages.
Let's check them out:
Complexity Custom validators can be more complex to implement than simple validation rules defined directly on model attributes. Defining custom validation logic in a separate class requires an understanding of Rails' validation system and can be more difficult to debug.
Learning Curve Defining custom validators requires a solid understanding of Ruby on Rails and its validation system, which may require additional learning and training for developers who are new to the framework.
Steps to implement Custom validators
Check Part III (Article in progress).
Conclusion
In conclusion, using custom validations in separate classes with Ruby on Rails can be a powerful tool for simplifying complex validation rules and promoting code reuse.
By following the steps outlined in this article, you have a solid understanding of how validators work in Ruby on Rails.
Whether you are a seasoned Rails developer or just starting out, custom validators can help you build more robust and maintainable applications.
Part III is going to cover the implementation of custom validators.
Celebrate
You've come to the end of the article, kudos! you did a great job. You can definitely celebrate!
Final thoughts
That's all for today. Thanks for reading this article.
I hope it helped you. Let me know if you have any questions.
Your thoughts, suggestions and corrections are more than welcome.
By the way, feel free to drop your suggestions on new blog articles.
Hope to see you next time.