I'm using Ruby 3.0.2 and trying to validate using ActiveRecord.
I want to validate user input that is a string but want treat the parts of the input as a numbers so that I can apply some logic to it.
The input needs to look something like this
21-10
I will use regex to ensure that there is a '-' between the two numbers, but I want to be able to validate the numbers to ensure that:
- One of the two sets of numbers is 21
- Both numbers cannot be larger than 21 unless the difference between them is two apart from each other
My challenge is being able to treat parts of a string as numbers with validation.
An example of input that would be valid/invalid:
11-21 // valid
10-23 // invalid because 23 > 21
11-11 // invalid because neither numbers are 21
22-24 // valid because 22 & 24 within 2 of each other
Any help appreciated!
CodePudding user response:
That can be done with a custom validation method like this:
# in the model
validate :range_string_has_validate_pattern
private
def range_string_has validate_pattern
parts = range_string.split('-') # assuming the attribute is named `range_string`
if parts.size != 2
errors.add(:range_string, "does not contain two parts separated by a '-'")
return
end
begin
parts[0] = Integer(parts[0])
parts[1] = Integer(parts[1])
rescue
errors.add(:range_string, "does not contain two numbers")
return
end
return if parts[0] == 21 || parts[1] == 21
return if (parts[0] - parts[1]).abs == 2
errors.add(:range_string, "does not match requirements")
end
CodePudding user response:
I would go with pattern matching (yay for modern ruby) and a custom validator method
validates :your_attribute, format: { with: /\A\d -\d \z/ }
validate :string_format
def string_format
# do not attempt if the format is wrong
return if errors.where(:your_attribute).present?
case your_attribute.split('-').map(&:to_i)
in [..20, ..20]
error.add(:your_attribute, 'Both numbers are less than 21')
in [..20, 22..] | [22.., ..20]
error.add(:your_attribute, 'One is less the other is more')
in [22.. => x, 22.. => y] if y - x > 2 or x - y > 2
error.add(:your_attribute, 'Difference is too big')
else
return
end
end