-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce value objects for complex parameter types #414
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! I think it makes sense to ship an initial version and iterate.
(There's a problem with tests though.)
565a002
to
f794bb3
Compare
cc @Shopify/rails @Shopify/core-stewardship |
cc @etiennebarrie could I get your 👀 on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand we want to make it real easy to deal with array of ids, but I think we should try to keep true to the roles each part of the framework need to play (types vs validations, etc.).
There is something in ActiveModel:Type::Integer that raises but it's closer to correctness than validation: https://github.com/rails/rails/blob/v6.1.3.2/activemodel/lib/active_model/type/integer.rb#L49
The DB would raise otherwise anyway.
I think I need to think about it more, I'm still not entirely sure what the solution would look like.
@etiennebarrie I can get on board with your perspective 😄 My inclination was to treat input data with a lot of caution, being pretty strict about what was expected and raising if it didn't conform to those expectations. You're right about Active Record types though - they're super loose in terms of how they coerce data, and they mostly just resort to Let's go with just performing the coercion for users, and returning nil if the input can't be parsed properly into the intended value type - it can be up to users to define further validations on their Tasks if they need more safeguards in place. |
b727463
to
ca85209
Compare
ca85209
to
88c4796
Compare
For now, I've opted to introduce the value types without any of the validations, and I've added a note in the README:
We may want to offer custom validations eventually (as you'd suggested), but I'm not sure what makes the most sense right now and so I'd prefer to defer until we have some feedback from users on what sort of custom validators would bring value. |
We've agreed to put this on pause until we have more info. I've opened #432 in the meantime to keep track of this feature. |
@adrianna-chang-shopify can this be closed? |
Closing, I think we've determined that there isn't enough of a demand for a feature like this, and we weren't quite happy with the API in this PR. |
We can offer users some custom parameter type objects to handle simple input validation + appropriate casting for more complex parameter types (the two we've talked about so far are arrays of strings & arrays of integers).
test/dummy/app/tasks/maintenance/params_task.rb
demonstrates how a Task author would use one of these types in their Task. This way, users don't have to copy-pasta a regex across Tasks, and they also get typecasting for free without having to cast their user input themselves in the Task.The regexes right now are pretty simple.
For array of integers: We accept a comma-delimited series of integers. We allow zero or one whitespace at the start or end of the string, before and after commas, and before and after the integers. (We could make it accept any amount of whitespace here).
For array of strings: We accept a comma-delimited series of strings (alphanumeric characters). I've just applied the same whitespace pattern matching as the integer array, although these will be included in the typecast result (we could discard additional whitespace at the start / end of the strings we parse? Not sure how fancy we want to get here)
Feedback welcome! 🤗 I would like to get an initial version of this ship and iterate as necessary though without getting too invested in the details 😉