app/validators/weekday_validator.rb
class WeekdayValidator < ActiveModel::EachValidator
WEEKDAY_ABBREVIATIONS = %w[Sun Mon Tue Wed Thu Fri Sat].freeze
WEEKDAY_STRING_NUMS = %w[1 2 3 4 5 6 7].freeze
def validate_each(record, attribute, _value)
value = record.read_attribute_before_type_cast(attribute)
default_message = "#{value} #{I18n.t('errors.messages.invalid_weekday')}"
unless valid_weekday_num?(value) || valid_weekday_name?(value)
record.errors.add(attribute, (options[:message] || default_message))
return
end
convert_value_to_integer(record, attribute, value)
end
private
def valid_weekday_num?(value)
(value.is_a?(Integer) && value.to_i.between?(1, 7)) || valid_string_num?(value)
end
def valid_string_num?(value)
WEEKDAY_STRING_NUMS.include?(value)
end
def valid_weekday_name?(value)
value.is_a?(String) && starts_with_weekday_abbreviation?(value)
end
def starts_with_weekday_abbreviation?(value)
WEEKDAY_ABBREVIATIONS.select { |abbr| value.start_with?(abbr) }.present?
end
def convert_value_to_integer(record, attribute, value)
record[attribute] = value.to_i if valid_weekday_num?(value)
record[attribute] = wday_name_to_int(value) if valid_weekday_name?(value)
end
def wday_name_to_int(value)
Date.parse(value).strftime('%u').to_i
end
end