Home > Net >  Inherited Hanami validators
Inherited Hanami validators

Time:06-13

I have Hanami 1.3.3 and two validators there: for create and update actions like these

module Validators
  module MyEntities
    class Create
      include Hanami::Validations::Form
      include Validatable

      messages :i18n

      validations do
        required(:first_attr).filled(:bool?)
        required(:second_attr).filled(:int?)

        required(:attr_for_create).filled(:str?)
      end
    end
  end
end
module Validators
  module MyEntities
    class Update
      include Hanami::Validations::Form
      include Validatable

      messages :i18n

      validations do
        required(:first_attr).filled(:bool?)
        required(:second_attr).filled(:int?)

        required(:attr_for_update).filled(:str?)
      end
    end
  end
end

In fact, the number of validation rules is more than twenty

As you see there is a lot of repetitive code here

I want to DRY it and use some inheritance

I couldn't find some receipts for this. Just discussion in GitHub issue. Outcome of that discussion: it's very tricky

How to use inherited validators in Hanami?

CodePudding user response:

To answer this question, we need to look at the source code of the library

As you see there is a validations method in Hanami validations gem

This method builds schema for validation. Among other things, the block passed to this method is used. It is the block with those validations rules that we write in our validators inside the application

To use inheritance, we can overwrite validations method in the parent class and join two blocks there: basic parent rules and child rules

To do this, we need instance_eval method

module Validators
  module MyEntities
    class Base
      include Hanami::Validations::Form
      include Validatable

      messages :i18n

      class << self
        def validations(&rules)
          schema_predicates = __predicates

          base   = _build(predicates: schema_predicates, &_base_rules)
          schema = _build(predicates: schema_predicates, rules: base.rules, &my_entity_rules(&rules)) # overwrite just here
          schema.configure(&_schema_config)
          schema.configure(&_schema_predicates)
          schema.extend(__messages) unless _predicates.empty?

          self.schema = schema.new
        end

        private

        def my_entity_rules(&rules)
          Proc.new do
            instance_eval(&rules) # use child rules

            required(:first_attr).filled(:bool?)
            required(:second_attr).filled(:int?)
          end
        end
      end
    end
  end
end
module Validators
  module MyEntities
    class Create < Base
      validations do
        required(:attr_for_create).filled(:str?)
      end
    end
  end
end
module Validators
  module MyEntities
    class Update < Base
      validations do
        required(:attr_for_update).filled(:str?)
      end
    end
  end
end
  • Related