LoginSignup
11
8

More than 3 years have passed since last update.

Rubyでvalidationするdry-validationの基本のキ

Last updated at Posted at 2020-02-27

はじめに

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)
11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8