Rails validating values in array
Solution 1
I don't think that default Rails validators will do the trick here, you can do this though:
validate :validate_wdays
def validate_wdays
if !wdays.is_a?(Array) || wdays.any?{|d| !(0..6).include?(d)}
errors.add(:wdays, :invalid)
end
end
Solution 2
I'm not certain whether there are easier ways to handle this within the existing Rails validation structure. You've got an odd case that the validators weren't really built to handle. You might need to write a custom validator for something like this (assuming an existing validation extension gem isn't available). Something like this:
class ArrayInRangeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, valueArray)
valueArray.each do |value|
record.errors.add "#{attribute} - #{value}", (options[:message] || "is not in the acceptable range") unless (1..6).include?(value)
end
end
end
and then in your model:
class Schedule < ActiveRecord::Base
include ActiveModel::Validations
validates :wdays, :presence => true, :array_in_range => true
... other model stuff
end
Solution 3
I created this gem: https://github.com/rafaelbiriba/active_model_validates_intersection_of
Basicaly, you can use like:
class User < ActiveRecord::Base
DEFAULT_PERMISSION = ["read", "write", "share"]
validates_intersection_of :permission, in: DEFAULT_PERMISSION
end
and if you try:
user = User.new(permission: ["read", "share"])
user.valid? #true
user = User.new(permission: ["read", "admin"])
user.valid? #false
Enjoy! Comments, pull requests and feedbacks is always welcome.
Solution 4
The accepted answer didn't really do this correctly in my opinion. If someone sets wdays = 'meow'
it'll set it to empty array wdays == []
without warning.
Type Casting is happening you ask for wdays
in that method. It's already converting the data into an array if it's invalid.
wdays_before_type_cast
should be used instead of wdays
when checking type.
validate :validate_wdays
def validate_wdays
errors.add(:wdays, :invalid) if wdays_changed? && !wdays_before_type_cast.is_a?(Array)
errors.add(:wdays, :invalid) if wdays.any? { |d| (0..6).exclude?(d) }
end
Related videos on Youtube
Comments
-
bsiddiqui almost 2 years
In my Schedule model I want to add some validation to the :wdays field, which is an int[]. I only want values 0..6 to be valid
Valid
Schedule.wdays = [0,1,6]
Invalid
Schedule.wdays = [0,1,10]
I tried using
validates :wdays, inclusion: { in: [0, 1, 2, 3, 4, 5, 6] }
and
validates :wdays, inclusion: { in: 0..6 }
but neither works
What is the proper way to validate the values in an array in your model?
-
Paul Richter over 9 years@tirdadc I added some of the updates from your edit, however can you verify that the name of the validator must be an underscored version (that it should be
array_in_range
rather thanarrayInRange
? Do you know of any documentation on that convention? -
Vadym Tyemirov about 7 yearsthe name of the validator should be underscored
-
Arian Faurtosh over 4 yearsThis doesn't work fully... if someone sets
wdays = 'meow'
it'll set it to empty array[]
without warning. Something above the stack is happening where it's already converting the data into an array if it's invalid