はじめに
RubyでAPIを作成する際にvalidationをいい感じにしてくれるgemを探したところ、dry-validationに行き着きました。
ただし、公式のリファレンスではよく分からないとか調べても古いバージョンの話だったとかがあったので、メモとして執筆時点で分かったことをメモとして残します。
環境
dry-validation 1.4
https://dry-rb.org/gems/dry-validation/1.4/
Gemのインストール
gem install dry-validation
gem install dry-struct
アプリケーションで使用するための基底クラスの作成
デフォルトだとメッセージが英語なので、日本語にするためにはconfigの設定が必要です。
なので基底クラスを使ってまとめて設定します。
class ApplicationContract < Dry::Validation::Contract
config.messages.default_locale = :ja
config.messages.backend = :yaml
config.messages.load_paths << 'config/contract/error.yaml'
end
メッセージはconfig.messages.load_paths
に設定した箇所に置いてください。
中身は以下のような感じです。
詳しいconfigの意味とかは公式のリファレンスで十分なので、そちらをご覧ください。
ja:
dry_validation:
errors:
rules:
{column_name}:
filled?: '必須です'
int?: '数字じゃありません'
date?: '日付じゃありません'
string?: '文字列じゃありません'
一番上にロケールを書く以外はフォーマットに沿って書いてあげる必要があります。
validation class
基本的な設定ができたので、実際にvalidationするためのクラスを例に使い方を書いていきます。
まずはサンプルをご覧ください。
class FormContract < ApplicationContract
params do
required(:start_date).filled(:date)
required(:end_date).filled(:date)
optional(:id).filled(:integer)
required(:name).maybe(:string)
end
rule(:end_date, :start_date) do
key(:start_date).failure('開始日は終了日よりも後ろにしてください') if values[:end_date] < values[:start_date]
end
単項目チェック
単項目はprams部分に記述します。
params do
required(:start_date).value(:date)
required(:end_date).filled(:date)
optional(:id).filled(:integer)
required(:name).maybe(:string)
end
パラメータチェック
パラメータが必須であるか任意であるかを記述します。
必須である場合はrequired
、任意である場合はoptional
で宣言します。
値チェック
値チェックはいくつか種類があります。
ここでは簡単なチェックのみで、パラメータのチェックを正規表現使ってやりたいといったチェックは別で行う必要があります。(後述)
filled
値の存在チェック + 型変換しての型チェックです。
値が存在しない場合は存在しないエラーとなり、値があり型変換後の型が違ったら型エラーとなります
# emptyエラー
{locale}.dry_validation.errors.filled?
# 型エラー
{locale}.dry_validation.errors.rules.{column_name}.int?
{locale}.dry_validation.errors.rules.{column_name}.str?
{locale}.dry_validation.errors.rules.{column_name}.date?
ちなみにfilledの引数に型を入れてるから型チェックしてくれるだけで、引数がなければ型チェックをスキップすることも可能です。
# 型チェックあり
required(:end_date).filled(:date)
# 型チェックなし
required(:end_date).filled()
value
厳密な型チェックです。
こちらはfilledと違って厳密な型チェックが行われます。
厳密な型チェックなので、formのパラメータをそのまま与えてvalidationするという用途には向いてません。
(formから渡ってきた値はstring扱いとなるため)
型チェックのみのため、型が違ったエラーしか返ってきません。
{locale}.dry_validation.errors.rules.{column_name}.int?
{locale}.dry_validation.errors.rules.{column_name}.str?
{locale}.dry_validation.errors.rules.{column_name}.date?
maybe
こちらも厳密な型チェックですが、値がnilの場合はチェックされません。
ただし、stringのblankはチェック対象となるため、注意が必要となります。
{locale}.dry_validation.errors.rules.{column_name}.int?
{locale}.dry_validation.errors.rules.{column_name}.str?
{locale}.dry_validation.errors.rules.{column_name}.date?
チェックをしたくない場合
チェックを行いたくない場合は何も書かなければOKです。
パラメータとしては必須だけど、2つの値のどちらかが入っていれば良いといったケースですね。
相関チェックや複雑なチェック
そういうのはrule
に記載していきます。
エラーが発生した場合は、どのkeyにどんなエラーがあったかを設定していく形です。
rule
に設定するキーも1〜n個引数が取れるので、全部こっちでvalidationさせることも可能です。
rule(:end_date, :start_date) do
key(:start_date).failure('開始日は終了日よりも後ろにしてください') if values[:end_date] < values[:start_date]
end
呼び出し方
呼び出しはnew
してcall
すれば良いです。
下のサンプルはrailsのparamsをそのまま引数として使う場合です。
call
にはHash
を引数としてあげればあとはやってくれます。
FormContract.new.call(params.permit!.to_h)