Techioz Blog

Ruby でドライ検証を使用してネストされた/再利用可能なバリデータを作成する

概要

住所の検証コントラクトを設定したいとしますが、ユーザーとコーヒー ショップの検証コントラクトも設定したいとします。どちらにも住所が含まれていますが、UserContract と CoffeeShopContract で AddressContract を再利用することはできますか?

たとえば、検証したいデータは次のようになります。

# Address
{
    "first_line": "100 Main street",
    "zipcode": "12345",
}

# User
{
    "first_name": "Joe",
    "last_name": "Bloggs",
    "address:" {
        "first_line": "123 Boulevard",
        "zipcode": "12346",
    }
}

# Coffee Shop
{
    "shop": "Central Perk",
    "floor_space": "2000sqm",
    "address:" {
        "first_line": "126 Boulevard",
        "zipcode": "12347",
    }
}

解決策

はい、スキーマを再利用できます (参照: スキーマの再利用)

次のようになります。

require 'dry/validation'
class AddressContract < Dry::Validation::Contract 
  params do 
    required(:first_line).value(:string) 
    required(:zipcode).value(:string) 
  end
end

class UserContract < Dry::Validation::Contract 
  params do
    required(:first_name).value(:string)
    required(:last_name).value(:string)
    required(:address).schema(AddressContract.schema)
  end
end 


a = {first_line: '123 Street Rd'}
u = {first_name: 'engineers', last_name: 'mnky', address: a }

AddressContract.new.(a)
#=> #<Dry::Validation::Result{:first_line=>"123 Street Rd"} errors={:zipcode=>["is missing"]}>
UserContract.new.(u)
#=> #<Dry::Validation::Result{:first_name=>"engineers", :last_name=>"mnky", :address=>{:first_line=>"123 Street Rd"}} errors={:address=>{:zipcode=>["is missing"]}}>

あるいは、スキーマ ミックスインを作成することもできます。

AddressSchema = Dry::Schema.Params do 
  required(:first_line).value(:string) 
  required(:zipcode).value(:string) 
end 

class AddressContract < Dry::Validation::Contract 
    params(AddressSchema) 
end

class UserContract < Dry::Validation::Contract 
  params do
    required(:first_name).value(:string)
    required(:last_name).value(:string)
    required(:address).schema(AddressSchema)
  end
end