Giter Site home page Giter Site logo

Whitelist keys about dry-validation HOT 24 CLOSED

dry-rb avatar dry-rb commented on May 18, 2024
Whitelist keys

from dry-validation.

Comments (24)

solnic avatar solnic commented on May 18, 2024 5

This is now done. You can configure schema's input processor, ie:

Dry::Validation.Schema do
  configure do
    config.input_processor = :sanitizer
  end

  key(:email).required

  key(:age).maybe(:int?, gt?: 18)

  key(:address).schema do
    key(:city).required
    key(:street).required
  end
end

result = schema.(
  email: 'jane@doe',
  age: 19,
  such: 'key',
  address: { city: 'NYC', street: 'Street', wow: 'bad' }
)

result.output
# {  email: 'jane@doe', age: 19, address: { city: 'NYC', street: 'Street' }

This comes with a bonus - a sanitization input processor holds information about the schema structure and types. It's using dry-types' hash with a safe constructor (which provides sanitization), and you have type definitions that you can use for some introspection. In example:

schema = Dry::Validation.Schema do
  configure { config.input_processor = :sanitizer }

  key(:email).required(:str?)
  key(:admin).required(:bool?)
  key(:age).maybe(:int?)
end

types = schema.input_processor.type.options[:schema]

puts types[:email]
# #<Dry::Types::Definition primitive=String options={}>

puts types[:admin]
# #<Dry::Types::Sum:0x007fe86b53c270 @left=#<Dry::Types::Definition primitive=TrueClass options={}>, @right=#<Dry::Types::Definition primitive=FalseClass options={}>>

puts types[:age]
# #<Dry::Types::Sum:0x007fe86b9da250 @left=#<Dry::Types::Definition primitive=NilClass options={}>, @right=#<Dry::Types::Definition primitive=Integer options={}>>

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024 1

Hey, that's great! Thank you very much for your effort on this :)

from dry-validation.

kwando avatar kwando commented on May 18, 2024

Dry::Data['hash'] is your friend.

https://github.com/dryrb/dry-types#hashes

from dry-validation.

ineu avatar ineu commented on May 18, 2024

Sorry, I don't really understand how it is related to whitelisted attributes. I don't want to enforce key presence, I want to make sure that no other keys but allowed can be passed.

from dry-validation.

kwando avatar kwando commented on May 18, 2024

It is not forcing you to have certain keys.

white_lister = Dry::Data['hash'].schema(bar: 'string', baz: 'string')
white_lister.call(params) # => only "white listed keys"

Using Dry::Validation::Schema

result = my_form_validation_schema.call(params)
if result.errors.empty?
  result.params # => only contains keys specified in the schema, i.e "white listed"
end

Note that you can have optional keys in a validation schema too.

from dry-validation.

ineu avatar ineu commented on May 18, 2024

That's exactly what I needed, thank you.
Do I have to use Dry::Validation::Schema::Form for this to work? As of dry-validation 0.6.0 Schema::Form seems to be broken:

[1] pry(main)> UpdateProfileSchema.new.call('foo' => 123).params
NoMethodError: undefined method `each_with_object' for nil:NilClass
from /home/ineu/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-data-0.5.1/lib/dry/data/type/hash.rb:51:in `schema'

where UpdateProfileSchema is empty:

class UpdateProfileSchema < Dry::Validation::Schema::Form
end

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024

Hey,

I don't see this happening with params method (which, by the way, has been renamed to output in master):

require 'dry-validation'

class Schema < Dry::Validation::Schema
  key(:email) { |email| email.filled? }

  key(:age) do |age|
    age.int? & age.gt?(18)
  end
end

schema = Schema.new

schema.call(email: '[email protected]', age: 19, other: 'aha!').params
# => {:email=>"[email protected]", :age=>19, :other=>"aha!"}

from dry-validation.

solnic avatar solnic commented on May 18, 2024

I'd consider this as a bug. schemas should only output defined keys. I'll fix that in next release.

from dry-validation.

kwando avatar kwando commented on May 18, 2024

@waiting-for-dev yeah, currently you need to check the result for errors first.

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024

Ok, thanks you both for the quick feedback

from dry-validation.

solnic avatar solnic commented on May 18, 2024

BTW I'm planning to experiment with a setup where separate schemas are used for pre-filtering input and then actual validation schemas can be inferred from these in order to apply additional business validation rules. This way we could have pure application validation schemas with business rules and a nice sanitization layer in front of it. The benefit would be a really good separation of concerns where input is sanitized and properly coerced so that we don't have to worry about our business validation process to crash on some stupid type-related issues. Currently my thinking is that handling both in one place is too much complexity and it mixes too many concerns (ie type coercions vs applying a business rule to a coerced value).

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024

And do you think this should be in dry-validation library or in a new one? I'm not taking side, yet, but I'm thinking whether sanitizing and validating business logic rules are too different responsibilities or not.

I have these doubts because, in my current situation, I need to perform one sanitation or another depending on the user, because not all users are allowed to update the same set of attributes.

In this scenario and with current dry-validation approach, I would need different schemes for each situation and I should perform the appropriate schema selection in a controller or service layer. I'm thinking whether this is too overkilling or it may exists a different kind of schemes (or whatever name) which would take the user as an argument... Something like:

# Everybody can update `quantity` attribute, but only users with `amount_updater` role can update `amount` attribute
class Schema < Dry::SanitationSchema
  key(:amount) { |amount, user| user.has_role?(:amount_updater) & amount.str? }
  key(:quantity) { |quantity| quantity.float? }
end

params = Request.give_me_the_params
user = User.give_me_an_user
schema = Schema.new
schema.call(params, user)

On the other side, different schemes would be better for very complex scenarios (but anyway you would be able to do that).

This could be a complete replacement (and improvement) for strong-parameters, without the need of carrying all business logic features along if people don't want to use them.

from dry-validation.

solnic avatar solnic commented on May 18, 2024

@waiting-for-dev I don't think you you would need separate schemas for each scenario. You just need a context-aware schema where your user is the context. So we can make something like that possible:

class Schema < Dry::Validation::Schema
  key(:amount).maybe

  rule(:amount_valid) do
    account_updater? & value(:amount).filled?
  end

  def account_updater?
    user.has_role?(:amount_updater)
  end
end

schema.with(user: user).call(params)

from dry-validation.

solnic avatar solnic commented on May 18, 2024

@waiting-for-dev oh and no, there's no need for a new library, I'm just trying to figure out how exactly I want to use this one :)

from dry-validation.

blelump avatar blelump commented on May 18, 2024

@solnic , running validation against certain context (with(x: :y)) definitely sounds like a good idea 👍

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024

Oh, great, I didn't know about the with method :D My fault. Thank you!!

from dry-validation.

solnic avatar solnic commented on May 18, 2024

@waiting-for-dev uhm, I wrote that we can make it possible, it's not implemented yet :)

from dry-validation.

kwando avatar kwando commented on May 18, 2024

Damn, I was already excited by that =P

from dry-validation.

solnic avatar solnic commented on May 18, 2024

I'll add it tomorrow

from dry-validation.

kwando avatar kwando commented on May 18, 2024

❤️

from dry-validation.

solnic avatar solnic commented on May 18, 2024

@waiting-for-dev @kwando Schema#with is in master, see spec

from dry-validation.

solnic avatar solnic commented on May 18, 2024

Anyhow, I'm now wondering if Schema should remove undefined keys or not. Form does do that because it uses hash type from dry-types to pre-process the input. I feel like this should actually be optional for "plain" schemas. I don't think that schemas must absolutely always sanitize the input...any thoughts?

from dry-validation.

waiting-for-dev avatar waiting-for-dev commented on May 18, 2024

Hey! Many, many thanks @solnic :) Now I'm out for three weeks without the computer, but when I come back I'll try it.

About your comment, to be honest I'm not sure. Looking for a way to sanitize has been my first approach to dry-validation in a project, so I have no experience in other use cases. But surely it makes more sense to make it optional, or you'll end up with another issue asking for the opposite :)

from dry-validation.

ineu avatar ineu commented on May 18, 2024

That's great. Thank you, @solnic

from dry-validation.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.