Rails validate format with regex - ruby-on-rails

In my rails app, I want to validate input on a string field containing any number of keywords (which could be more than 1 natural language word (e.g. "document number")). To recognize the individual keywords, I am entering them separated by ", " (or get their end by end of string).
For this I use
validates :keywords, presence: true, format: { with: /((\w+\s?-?\w+)(,|\z))/i, message: "please enter keywords in correct format"}
It should allow the attribute keywords (string) to contain: "word1, word2, word3 word4, word5-word6"
It should not allow the use of any other pattern. e.g. not "word1; word2;"
It does incorrectly allow "word1; word2"
On rubular, this regex works; yet in my rails app it allows for example "word1; word2" or "word3; word-"
where is my error (got to say am beginner in Ruby and regex)?

You need to use anchors \A and \z and modify the pattern to fit that logic as follows:
/\A(\w+(?:[\s-]*\w+)?)(?:,\s*\g<1>)*\z/
See the Rubular demo
Details:
\A - start of string
(\w+(?:[\s-]*\w+)?) - Group 1 capturing:
\w+ - 1 or more word chars
(?:[\s-]*\w+)? - 1 or 0 sequences of:
[\s-]* - 0+ whitespaces or -
\w+ - 1 or more word chars
(?:,\s*\g<1>)* - 0 or more sequences of:
,\s* - comma and 0+ whitespaces
\g<1> - the same pattern as in Group 1
\z - end of string.

Related

what does the instruction "name =~ /[A-Z].*/"?

I'm studying ruby ​​on rails and I'm seeing a code, but I could not understand how it actually works.
''''ruby
validate: first_letter_must_be_uppercase
private
def first_letter_must_be_uppercase
errors.add ("name", "first letter must be uppercase") unless name =~ /[A-Z].*/
end
The code is basically checking that the string should contain the first letter in the upper case using the regular expression
explanation:
/[A-Z].*/
[A-Z] - Checks for any capital letter from A to Z
. - checks for any wildcard character
* - matches for 0 to any number of repetition.
To sum up
The input string should match the following format - A capital letter from A-Z and then should have 0 to any number of wildcard characters
You can check it on Rubular
EDIT
As pointed out by #vasfed if you want to match the first character the regex need to be changed to
/\A[A-Z].*/
\A - Ensure start of the string

Brakeman insufficient validation warning of regex anchors

I'm trying to implement a validation in a model like this.
validates_format_of :field, with: /[0-9]/, message: 'must have at least one number (0-9)'
Brakeman detects this a Format Validation security issue and it recommends to add the anchors between the regular expression.
Insufficient validation for 'field' using /[0-9]/. Use \A and \z as anchors near line 54
If I add those anchors, the regular expression stops working, so I don't know what to do in this case. Here's the tests I made using rails c.
"asdf1234".match(/\A[0-9]\z/) # => nil
"foobar1".match(/\A[0-9]\z/) # => nil
I need that the method return #<MatchData "1"> in both cases.
Any ideas?
Thanks.
If you need to match a string that has at least 1 digit inside, and any other chars before and after, you may use
/\A[^0-9]*[0-9].*\z/m
or just
/\A.*[0-9].*\z/m
Details
\A - start of string
[^0-9]* - zero or more chars other than an ASCII digit
[0-9] - an ASCII digit
.* - any 0+ chars, as many as possible, up to the
\z - end of string.
The m modifier makes . match any char, including a line break char.
Actually, /\A.*[0-9].*\z/m will be a bit slower, as the first .* will grab all the string at once and then will backtrack to find the last digit. The first one is more optimized.

Regex for letters, numbers, dashes only?

I am trying to validate a second level domain (everything before the .com and after the https://) in Ruby so that I can pass it into my namecheap api requests. Here is what I have so far, but I am not familiar with regex
validates_format_of :sld, with: [a-zA-Z0-9-]
no spaces allowed
no special characters allowed
however, dashes are allowed
cannot start with a dash
cannot end with a dash
I know that uppercase characters do not work in domain names, but I don't want to make users enter their text again. I will downcase the user input and show a flash message on the next page.
How about
validates_format_of :sld, with: /\A[a-z\d][a-z\d-]*[a-z\d]\z/i
Explanation:
\A - match beginning of string
[a-z\d] - match any letter from a-z or number from 0-9 once
[a-z\d-] - match any letter from a-z, number from 0-9, or dash zero or more times
[a-z\d] - match any letter from a-z or number from 0-9 once
\z - match end of string
i flag - make matches case-insensitive
Note: this will only work for strings of length 2 or more. If you need to support single-character inputs,
I would just write a method that checks the string length and if it's a single character, ensure it's not a dash. If it's more than 2 characters, validate it with this regex.
This will probably work:
^[0-9A-Za-z](|[-0-9A-Za-z]{0,61}[0-9A-Za-z])$
Your string needs to start with a alphanumeric ([0-9A-Za-z])
Then, there are two choices ((|[-0-9A-Za-z]{0,61}[0-9A-Za-z])):
End of string
Between 0 and 61 alphanumeric or dash chars followed by an alphanumeric char. (For a maximum of 63 characters)
^ and $ are anchors
validates :sld, format: { with: /^(?!-)[-\w\d]{,63}(?<!-)$/i }
You can try out your regex at http://rubular.com/
^(?!-) - negative lookahead: cannot start with dash
[-\w\d] - match words \w, digits \d, or dash -
{,63} - match must be between 1 and 63 characters
(?<!-)$ - negative lookbehind: cannot end with dash
/i - case insensitive

Rails regex syntax error

I am trying to set a regex validation on a form with the code below. I want to allow any alphabetical character, including accents, numbers and hyphen, apostrophe, comma and space. This expression should match the result : "Tir à l'arc, 3d, danse"
validates :interest_list, tags: true, if: lambda { interest_list.any? }
validates :interest_list, format: { with: /\A[[:alpha:]\d-'’, ]\z/, message: "only allows letters, space, hyphen and apostrophe" }
But I have this error empty range in char class: /\A[[:alpha:]\d-'’,]\z/
Can anyone tell me what I'm doing wrong ?
Any - that appears inside a character class in any position other than the first or last is treated as a range, ie. [0-9] is shorthand for [0123456789]. This range is calculated based on the ASCII values.
You have \d-' in your regex and \d isn't valid to use for the start/end of a range. Probably what you want is to move - to the start or end of your []
/\A[[:alpha:]\d'’, -]\z/
...and to solve your next problem/question - as it is your regex will only match a single character, you probably also want a repeat on that character class, like a +:
/\A[[:alpha:]\d'’, -]+\z/
Error: Regex Construction ..
Invalid range end in character class
\A[[:alpha:]\d->>>HERE>>>'’, ]\z
\d - anything is invalid range because a range operator - cannot
specify a range between a class and anything else.
You'd need to escape the - to make it a literal \A[[:alpha:]\d\-'’, ]\z
or add it to the end or beginning \A[[:alpha:]\d'’, -]\z

rails 4 model text regex allow 0-9, a-z, links and email address

I am working with the following model validation and my tests are working except when I started adding the ability to include links bad characters are making it through :(
validates :application_process,
presence: true,
format: { with: %r{\A[\w\d .,:/-#&?]+\z}, message: :bad_format }
I want to allow the following:
A-Z
a-z
0-9
?
:
/
#
.
,
The regex you have contains a -. A hyphen inside a character class creates a range if it is not escaped and does not appear after a shorthand character class, a range, start or end of the character class.
So, if you need to match a literal hyphen escape it or place at the end of the character class (before ]).
To only match the characters and ranges you specify in the question, use
%r{\A[A-Za-z0-9?:/#.,]+\z}
To add a hyphen:
%r{\A[A-Za-z0-9?:/#.,-]+\z}
^

Resources