We have seen that built-in predicates as an expressive tool to get our job done with common use cases.

But what if our case is not common? We can define our own custom predicates.

Inline Custom Predicates

If we are facing a really unique validation that does not need to be reused across our code, we can opt for an inline custom predicate:

  1. require 'hanami/validations'
  2. class Signup
  3. include Hanami::Validations
  4. predicate :url?, message: 'must be an URL' do |current|
  5. # ...
  6. end
  7. validations do
  8. required(:website) { url? }
  9. end
  10. end

Global Custom Predicates

If our goal is to share commonly used custom predicates, we can include them in a module to be used in all our validators:

  1. require 'hanami/validations'
  2. module MyPredicates
  3. include Hanami::Validations::Predicates
  4. self.messages_path = 'config/errors.yml'
  5. predicate(:email?) do |current|
  6. current.match(/.../)
  7. end
  8. end

We have defined a module MyPredicates with the purpose to share its custom predicates with all the validators that need them.

  1. require 'hanami/validations'
  2. require_relative 'my_predicates'
  3. class Signup
  4. include Hanami::Validations
  5. predicates MyPredicates
  6. validations do
  7. required(:email) { email? }
  8. end
  9. end

Internationalization (I18n)

  1. require 'hanami/validations'
  2. module MyPredicates
  3. include Hanami::Validations::Predicates
  4. self.messages_path = 'config/errors.yml'
  5. predicate(:uuid?) do |input|
  6. !/[0-9a-f]{8}-
  7. [0-9a-f]{4}-
  8. [0-9a-f]{4}-
  9. [0-9a-f]{4}-
  10. [0-9a-f]{12}/x.match(input).nil?
  11. end
  12. end
  1. require 'hanami/validations'
  2. require_relative 'my_predicates'
  3. module Web
  4. module Controllers
  5. module Signup
  6. class Params < Hanami::Action::Params
  7. predicates MyPredicates
  8. validations do
  9. required(:id).filled(:uuid?)
  10. end
  11. end
  12. end
  13. end
  14. end
  1. module Web
  2. module Controllers
  3. module Signup
  4. class Create
  5. include Web::Action
  6. params Params
  7. def call(params)
  8. # ...
  9. end
  10. end
  11. end
  12. end
  13. end