Hanami version 0.8 has just been released. This version is major due to a number of reasons and features. I will be talking about just one, but the others are mostly bug fixes and improvements.

The biggest change is that the validations have been completely revamped. The new validations are built on top of dry-validations which is a much stricter and better validation approach. In a different post I will write about Dry-RB

dry-rb is a collection of next-generation Ruby libraries, each intended to encapsulate a common task

New validation interface

In the past versions, to validate form inputs in the controller/action. We used to do something like below:

Before:

module Web::Controllers::Users
  class Create
    include Hanami::Action

    params do
      param :user do
        param :username, presence: true
        param :password, presence: true
        param :email,    presence: true
      end
    end

    def call(params)
      if params.valid?
        @user = UserRepository.create(User.new(params[:user]))

        redirect_to('/users/' + @user.id)
      else
        status = 422
      end
    end

  end
end

Now you just do:

# ... snip
params do
  required(:user).schema do
    required(:username).filled(:str?)
    required(:password).filled(:str?)
    required(:email).filled(:str?)
  end
end
# ... snip

This i find very beautiful and it sticks to the old validation style, but more powerful.

If you are like me, I like to move my validations to a central place where I can reuse them for other apps in the Hanami stack, for example if you decide to have apps/api or apps/admin. Lets move the validations out, I will put mine in the lib/bookshelf/validations/ directory:-

# lib/bookshelf/validations/user_validations.rb
class UserParams < Hanami::Action::Params
  params do
    required(:user).schema do
      required(:username).filled(:str?)
      required(:password).filled(:str?)
      required(:email).filled(:str?)
    end
  end
end

# Then you can use it
# ...
def call(params)
  user_params = UserParams.new(params[:user])

  if user_params.valid?
    user = UserRepository.create(User.new(user_params))

    redirect_to("/users/#{user.id}")
  else
    status = 422
  end
end
# ...

Is there a better way? Lets chat about this on the Hanami chat and help improve this post.