Contracts & context validation

ver.1.0

What is the recommended, DRY way to use a contract along with a context?

For example let’s consider a model Device. Each Device can be a pc, a phone or a tablet.

I would like to validate the types differently but they would all share validation as Device.

For example for all types I would like to validate screen_size, but only for a pc I would like to validate a keyboard_type.

Edit:
I would like to share (inherit?) schema, but rules as well.

There’s no support for inheritance yet. It’ll be added eventually. For now you can just define rules that are run conditionally.

I’ve tried something like this:

class DeviceContract < Dry::Validation::Contract
  def initialize
    super
  end

  params do
    required(:screen_size).filled(:int?)
  end

  rule(:screen_size) do
    key.failure('invalid screen size') if value < 1
  end
end

class PcContract < DeviceContract
  def initialize
    super
  end

  params do
    required(:keyboard).filled(:str?)
  end

  rule(:keyboard_type) do
    key.failure('invalid keyboard type') if KEYBOARD_TYPES.exclude?(value)
  end
end

I call the PcContract and it seems to work (it validates keyboard_type but screen_size as well). Further, my experiments shown that it is seems to be possible to overwrite only some of the params defined in the base class and still use the rest.

Is there any contraindication against the above described inheritance? Am I missing something?

Rules are inherited but schemas are not, that’s why in this case it worked for you.