Dry-rb for Ruby on Rails microservice part 2: Validations

Dry-rb for Ruby on Rails microservice part 2: Validations
Average rating: 0
(0 votes)

validation-dogs-209x300This is the second tech post about less persistent microservices built on Ruby on Rails with help of DRY-rb utility framework.

In the first part we’ve discussed the usage of dry-types library. Now it’s turn to show how to validate parameters with the dry-validation. With its help we are going to mimic the ActiveModel validations API.

First of all, we need to implement the the same API as ActiveModel::Validations has, that’s how it looks like:

module Validatable                                                              
  extend ActiveSupport::Concern                                                 
                                                                                
  included do                                                                   
    extend ActiveModel::Naming                                                  
    extend ActiveModel::Translation                                             
                                                                                
    alias_method :attributes, :to_h                                             
  end                                                                           
                                                                                
  def read_attribute_for_validation(attr)                                       
    public_send(attr)                                                           
  end                                                                           
                                                                                
  def validate!                                                                 
    errors.clear                                                                
                                                                                
    @validated = true                                                           
    @validation = self.class.const_get(:Schema).call(to_h)                      
                                                                                
    @validation.messages.each do |field, field_errors|                          
      field_errors.each do |field_error|                                        
        errors.add(field, field_error)                                          
      end                                                                       
    end                                                                         
  end                                                                           
                                                                                
  def valid?                                                                    
    validate! unless @validated                                                 
    @validation.success?                                                        
  end                                                                           
                                                                                
  def errors                                                                    
    @_errors ||= ActiveModel::Errors.new(self)                                  
  end                                                                           
end

As you can see it implements the minimal methods we used before in the traditional Rails validations: `validate!`, `valid?`, and `errors`. For the simplicity we used the ActiveModel::Errors class in favour of implementing it by our own. 🙂

Now it’s time to show how dry-validations work together with dry-types. Welcome to the Box model:

class Box < Dry::Types::Struct                                                  
  include Validatable                                                           
                                                                                
  constructor_type(:schema)                                                     
                                                                                
  attribute :packing, Types::ZeroBox                                            
  attribute :clothes, Types::ZeroBox                                            
  attribute :drawings, Types::ZeroBox                                           
                                                                                
  Schema = ::Dry::Validation.Schema do                                          
    key(:packing) { int? & gteq?(0) & lteq?(100) }                               
    key(:clothes) { int? & gteq?(0) & lteq?(100) }                               
    key(:drawings) { int? & gteq?(0) & lteq?(100) }                             
  end                                                                      
end

 

The Box validates `packing`, `clothes`, and `drawings` properties with these: it must be an Integer within 0 and 100. It needs some proof, so:

describe Box, type: :model do                                     
  %i(packing clothes drawings).each do |field|                                  
    it "validates #{field} range" do                                            
      expect(described_class.new(field => '-1')).to_not be_valid                
      expect(described_class.new(field => '1')).to be_valid                     
      expect(described_class.new(field => 10)).to be_valid                      
      expect(described_class.new(field => '101')).to_not be_valid                
    end                                                                          
  end                                                                           
end

 

If you like dry-rb, but don’t know how to use it within Rails application, that’s it!

Rate this article, if you like it

Thanks! You’ve rated this material!

Got a project? Let's discuss it!

*By submitting this form you agree with our Privacy Policy.

Mailing & Legal Address

Syndicode Inc. 340 S Lemon Ave #3299, Walnut CA, 91789, USA

Visiting & Headquarters address
Kyiv Sofiivska 1/2a, 01001, Kyiv, Ukraine
Dnipro Hlinky 2, of. 1003, 49000, Dnipro, Ukraine
Email info@syndicode.com
Phone (+1) 9035021111