Trying to write correct validation.
I have symbols/letters which can be only used:
ALLOWED_SYMBOLS = %w(/ @ _ - ( ) . , : ? ' & ; " 0 1 2 3 4 5 6 7 8 9 A a Ā ā Ą ą Ä ä B b C c Č č D d E e Ē ē Ę ę Ė ė F f G g Ģ ģ H h I i Ī ī Į į Y y J j K k Ķ ķ L l Ļ ļ M m N n Ņ ņ O o Õ õ Ö ö P p Q q R r S s Š š T t U u Ū ū Ü ü V v W w Z z Ž ž X x)
Afterwards i'm trying to validate it
validates :reference inclusion: { in: ALLOWED_SYMBOLS, allow_blank: true }
But it's not working properly as if i'm writing 2 or more allowed symbols i get an error, it does not happen when i type only 1 allowed one.
Looking forward for your help. The idea is to only allow mentioned symbols(they can be duplicated and such)
Rails 5.2
CodePudding user response:
Your problem is that validating inclusion: {in: ...}
is saying "the value must be one of the items in the list" -- which is not what you want at all.
Instead, what you're trying to check is "does reference
only contain characters from this list?".
I would solve that with a regex. Suppose, for example, you wanted a string to only contain the characters a, b, c, d, ..., z
. Then you could check the format with:
/\A[a-z]*\z/
Where \A
means "start of string", \z
means "end of string" and [a-z]*
means "zero or more letters from the collection: a, b, c, ...., z
".
However, your scenario is a little more awkward because you don't have a nice character set/range like [a-z]
. You could write that very verbosely (but it's difficult to read/reuse the code):
/\A[\/@_ \-().,:?'&;"0123456789ĀāĄąÄäBb....]*\z/
Or, better, you could get a little fancy and convert the constant into a suitable regex:
/\A#{Regexp.union(*ALLOWED_SYMBOLS)}*\z/
And therefore your final answer is to replace this:
validates :reference inclusion: { in: ALLOWED_SYMBOLS, allow_blank: true }
With this:
validates :reference, format: { with: /\A#{Regexp.union(*ALLOWED_SYMBOLS)}*\z/ }
See also: https://guides.rubyonrails.org/active_record_validations.html