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 in: range matcher to validate_numericality_of #1512

Merged

Conversation

matsales28
Copy link
Member

@matsales28 matsales28 commented Oct 1, 2022

Closes: #1493

In Rails 7 was added a new option to validate numericality. You can use in: range to specify a range to validate an attribute.

# Before Rails 7
class User < ApplicationRecord
  validates :age, numericality: { greater_than_or_equal_to: 18, less_than_or_equal_to: 65 }
end

# After Rails 7
class User < ApplicationRecord
  validates :age, numericality: { in: 18..65 }
end

In this commit we are adding the support matcher to this new functionality, while also making a refactor on the numericality matchers that use the concept of submatchers.

We've created a new class (NumericalityMatchers::Submatcher) that's been used by NumericalityMatchers::RangeMatcher and NumericalityMatchers::ComparisonMatcher, this new class wil handle shared logic regarding having submatchers that will check if the parent matcher is valid or not.

Our new class Numericality::Matchers::RangeMatcher is using as submatchers two NumericalityMatchers::ComparisonMatcher instances to avoid creating new logic to handle this new option and also to replicate what was being used before this option existed in Rails (see example above)

In this commit we are adding:

  • NumericalityMatchers::RangeMatcher file to support the new in: range option.
  • Specs on ValidateNumericalityOfMatcherSpec file for the new supported option, only running on rails_versions > 7.
  • NumericalityMatchers::Submatchers file to handle having submatchers inside a matcher file.
  • Refactors to NumericalityMatchers::ComparisonMatcher.

@matsales28 matsales28 self-assigned this Oct 1, 2022
Closes: thoughtbot#1493

In Rails 7 was added a new option to validate numericality. You can use
`in: range` to specify a range to validate an attribute.

```ruby
class User < ApplicationRecord
  validates :age, numericality: { greater_than_or_equal_to: 18, less_than_or_equal_to: 65 }
end

class User < ApplicationRecord
  validates :age, numericality: { in: 18..65 }
end
```

In this commit we are adding the support matcher to this new
functionality, while also making a refactor on the numericality
matchers that use the concept of submatchers.

We've created a new class (`NumericalityMatchers::Submatcher`) that's
been used by `NumericalityMatchers::RangeMatcher` and
`NumericalityMatchers::ComparisonMatcher`, this new class wil handle
shared logic regarding having submatchers that will check if the parent
matcher is valid or not.

Our new class `Numericality::Matchers::RangeMatcher` is using as
submatchers two `NumericalityMatchers::ComparisonMatcher` instances to
avoid creating new logic to handle this new option and also to replicate
what was being used before this option existed in Rails (see example
above)

In this commit we are adding:

* NumericalityMatchers::RangeMatcher file to support the new `in: range`
  option.
* Specs on ValidateNumericalityOfMatcherSpec file for the new supported
  option, only running on rails_versions > 7.
* NumericalityMatchers::Submatchers file to handle having submatchers
  inside a matcher file.
* Refactors to NumericalityMatchers::ComparisonMatcher.
@matsales28 matsales28 force-pushed the feat/validate_numericality_of-in-matcher branch from 9699c78 to 14379aa Compare October 1, 2022 13:34
hash[qualifier[:name]] = qualifier[:validation_name]
def all_available_qualifiers
all_qualifiers.filter do |qualifier|
rails_version >= qualifier.fetch(:rails_version, rails_oldest_version_supported)
end
end
Copy link
Member Author

Choose a reason for hiding this comment

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

This method was not being used at all, I've deleted it, but happy to revert if it's needed in some way or not in the scope of this PR to make this change.

Comment on lines +2229 to +2233
if args
matcher.__send__(qualifier[:name], args)
else
matcher.__send__(qualifier[:name])
end
Copy link
Member Author

Choose a reason for hiding this comment

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

This method was causing an error because args when testing the in option was a range, and the splat operator was destructuring the range.

We were using the splat operator on args only to prevent passing it when it was nil, so I changed this method to reflect that better and not cause the error when using a range.

Happy to change to this other implementation if you think the use case of not destructuring is more clear when the argument is a range.

Suggested change
if args
matcher.__send__(qualifier[:name], args)
else
matcher.__send__(qualifier[:name])
end
if args.is_a? Range
matcher.__send__(qualifier[:name], args)
else
matcher.__send__(qualifier[:name], *args)
end

@matsales28
Copy link
Member Author

Happy to contribute to a gem that I used a lot. It was pretty challenging but a fun journey to make this PR because I didn't know the codebase at all.

I've tried to make a minor refactoring. If y'all think that's not in the scope of this PR, I'm happy to revert the changes and limit my PR only to add the new functionality, and any suggestions to make the code clearer / better are welcome! 😄

Copy link
Collaborator

@vsppedro vsppedro left a comment

Choose a reason for hiding this comment

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

Nice PR! I'm fine with all your changes, I haven't merged it yet because I'm wondering if @mcmire would like to take a look too.

Thanks!

@mcmire
Copy link
Collaborator

mcmire commented Oct 5, 2022

Hey! I skimmed over the PR. My initial thought is that I feel like I've done something similar in years past, where I've created an abstraction around a group of matchers rather than just one, but this particular implementation is really straightforward, so I like it. I'll give this a deeper dive today.

@rdsngit
Copy link

rdsngit commented Oct 25, 2022

@mcmire How is the review of this PR going? Does it look like it will be accepted into the shoulda-matchers codebase? No worries if you've been busy on other projects and haven't had time to look at it.

@mcmire
Copy link
Collaborator

mcmire commented Oct 25, 2022

I'm on vacation right now but honestly I'm fine with merging this PR as well. If there's duplication we can always refactor it out later, it's no big deal.

@rdsngit
Copy link

rdsngit commented Oct 25, 2022

I'm on vacation right now but honestly I'm fine with merging this PR as well. If there's duplication we can always refactor it out later, it's no big deal.

@mcmire thanks for the update, hope you enjoy the rest of your vacation :)

@vsppedro vsppedro merged commit 09bc260 into thoughtbot:main Oct 29, 2022
@vsppedro vsppedro mentioned this pull request Jan 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing Support for the numericality in: Range Validation
4 participants