Is it possible to use dry-validation to validate ruby objects?


#1

All the examples I’ve seen pass a hash to schema.call, however I am wondering if it is possible to pass a ruby object instead.

I am expecting that the validator checks the values of object attributes instead of the values of hash keys.

Am I misunderstanding the use case for dry-validation?


#2

The main intention for dry-validation is to validate data, usually coming in from the boundaries of your system (e.g. from user input or other untrusted/unknown sources), which is why it works with simple arrays and hashes as input data.

In a typical dry-rb-style app, by the time this data winds up encapsulated in rich objects, we’d expect the data to be valid.

Can you pass your objects’ attributes as a hash to your dry-validation schemas instead?


#3

Tim,

Thank you very much for your response. It really helped me in understanding the rationale behind dry-validation.

Regards,
Hector


#4

Hi, I know this thread is old but it’s still relevant to me so I think it might be a better idea to revive it than start a new one.

I have a system where the meaning of valid change with context. Typically a valid draft is not a valid published item.

I’d like to use dry validation to validate an object (my idea is an activerecord object but it could be anything ) because in this case the source is the database.

I hoped dry-validation would work with any kind of (nested) object but it seems it does not.

I do not think my case is so special so I’m reposting the same question : Is there a way to validate an object ? If not : will there be soon ? if not : what do you suggest to validate data from database ?

Thanks in advance :slight_smile:


#5

Hey, validating objects won’t be supported, dry-validation is for validating data exclusively, which are represented by ruby primitives (Hash, Array, String, etc).

what do you suggest to validate data from database ?

Dump them to arrays/hashes and then you can apply validation schemas, although that would not be a common use case.


#6

Ok, It’s the direction I took.

It’s a little strange to serialize an object graph in order to be able to validate it.

Do you think it may be a good idea to wrap an ActiveRecord in a kind of Delegator overriding the def [](key) which would call public_send(key) on its delegate and then wrap it again in the same Kind of Delegator?

That delegator would some kind of adapter for object graphs (in my case ActiveRecord but I can imagine a graph of Poros having the same behavior) to make it look like a hash.

In other terms, what’s the part of the Hash interface that you rely on as input? How hard would it be for another object to quack like a hash?


#7

This could do (I didn’t thoroughly test it though):

class ValidationProxy
  def initialize(model)
    @model = model
  end

  def [](attr)
    @model.public_send(attr)
  end

  def key?(attr)
    @model.attributes.key?(attr.to_s)
  end

  alias has_key? key?
end

class User < ActiveRecord::Base
end

Schema = Dry::Validation.Schema do
  required(:name).filled(:str?)
end

valid_user = User.new(name: 'foo')
invalid_user = User.new(name: '')

puts Schema.call(ValidationProxy.new(valid_user)).success? #=> true
puts Schema.call(ValidationProxy.new(invalid_user)).errors #=> {:name=>["must be filled"]}

#8

Thanks @smaximov ,

Actually I think we need to use respond_to? as implementation of key? and also wrap the result in a ValidationProxy if it is an ActiveRecord but those are implementations details.

My main question to @solnic was mostly about an interface for what it means to be a ValidationInput.
Of course the proxy needs key? and [] but does it need something else and how stable are those requirements ?

Would you be interested in a PR in that direction ? With tests and documentation of course :slight_smile:


#9

Please try not to do this. This is not, and will not be, a first-class feature in dry-validation.