Skip to content
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

Add ComparisonValidator to validate comparison of any objects #40095

Merged
merged 2 commits into from
Apr 24, 2021

Conversation

ChaelCodes
Copy link
Contributor

Summary

We allow for compare validations in NumericalityValidator, but these
only work on numbers. There are various comparisons people may want
to validate, from dates to strings, to custom comparisons.

validates_comparison_of :end_date, greater_than: :start_date

Other Information

My main reason for creating this validator is the number of workarounds for validating that a start_date begins before an end_date.

Instead of making something specific like a date validator, I thought it would be helpful to create a generic comparison validator, to support a variety of circumstances, including custom comparables.

guides/source/active_record_validations.md Outdated Show resolved Hide resolved
activemodel/lib/active_model/validations/comparison.rb Outdated Show resolved Hide resolved
activemodel/lib/active_model/validations/comparison.rb Outdated Show resolved Hide resolved
guides/source/active_record_validations.md Outdated Show resolved Hide resolved
### `comparison`

This check will validate a comparison between any two comparable values.
If an option is not passed, all validations pass. Each option accepts a value, proc, or symbol.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to suggest "supplied" to avoid passed/pass... but maybe it should just be an immediate error to define a comparison validation without any constraints?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any existing patterns for this? I think this is the first validator that needs checks to validate anything.

I leaned towards no error in case someone dynamically supplied options, and they were missing. I also thought if there were no constraints, then there should be no errors. I can also see the argument that an error could help nudge people who've misconfigured the comparison validator.

The way I see it, we have 3 options:
👀 Error if no options supplied
🚀 Pass if no options supplied
🎉 Validate if the attribute is comparable if no options supplied, making the checks optional

I don't have a strong preference, and they're all pretty easy to implement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it's taken me a silly amount of time to come back to this...

I believe this is what check_validity! is for. Numericality only does a typecheck [because it always implies the must-be-a-number constraint, even without any further options], but Length and Format have precedent for "you can supply any of these options, but must supply at least one (or for Format, exactly one).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I'll update the tests, code, and guide.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made the requested changes!

@matthewd
Copy link
Member

👋🏻!

What do you think about having NumericalityValidator inherit from this, such that it ends up being "make_sure_its_a_number && super"?

Worth considering as a future change, or probably not worth it?

@ChaelCodes
Copy link
Contributor Author

@matthewd
👋!

I tried out the inheritance and it ended up being more trouble than expected. With a decent refactor to NumericalityValidator though, I can add a Comparability module similar to Clusivity.
I'm working on that and will update soon!

@ChaelCodes
Copy link
Contributor Author

This PR is ready to review. Let me know if there are any other requested changes. I'd be happy to implement them.

Base automatically changed from master to main January 14, 2021 17:01
…omparable values.

We allow for compare validations in NumericalityValidator, but these
only work on numbers. There are various comparisons people may want
to validate, from dates to strings, to custom comparisons.

```
validates_comparison_of :end_date, greater_than: :start_date
```

Refactor NumericalityValidator to share module Comparison with ComparabilityValidator
* Move creating the option_value into a reusable module
* Separate COMPARE_CHECKS which support compare functions and accept values
* Move odd/even checks to NUMBER_CHECKS as they can only be run on numbers
@ChaelCodes
Copy link
Contributor Author

@rafaelfranca @matthewd I've just rebased to incorporate the new changes to NumericalityValidator, and renamed valid!, and invalid!. Please let me know if there's anything else I can do for this PR.

@rails-bot
Copy link

rails-bot bot commented Apr 24, 2021

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Thank you for your contributions.

@rails-bot rails-bot bot added the stale label Apr 24, 2021
@rails-bot rails-bot bot removed the stale label Apr 24, 2021
@matthewd matthewd merged commit 536a2c0 into rails:main Apr 24, 2021
@ChaelCodes ChaelCodes deleted the cc-comparablity-validator branch April 24, 2021 11:37
def check_validity!
unless (options.keys & COMPARE_CHECKS.keys).any?
raise ArgumentError, "Expected one of :greater_than, :greater_than_or_equal_to, "\
":equal_to, :less_than, :less_than_or_equal_to, nor :other_than supplied."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChaelCodes Typo: nor -> or

I would also add option in the exception message like: ... or :other_than option supplied.

kamipo added a commit that referenced this pull request Apr 25, 2021
It was accidentally changed in #40095.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants