Formfield should have 4 numbers followed by 2 letters in Rspec - ruby-on-rails

I am writing an application where a user could fill in their zipcode. In the Netherlands a zipcode has a format of 4 times a number, followed by 2 letters. For example, 1234AB.
In my test I have written so far:
before(:each) do
#zipcode = Zipcode.new
#zipcode.zipcode = "1234AB"
#zipcode.house_number = 2
end
it "should have a valid zipcode" do
#zipcode.zipcode.should_not be_empty
#zipcode.zipcode.should be_a(String)
#zipcode.zipcode.length.should == 6
end
How ca I write the test that it checks if there are 4 numbers followed by 2 letters? And how should I write that in code it self?

You will want to use a Regex (regular expression). For your example, it would be quite simple:
/\A[0-9]{4}[A-Z]{2}\z/
which means: Line start, 4 times a digit, 2 times a uppercase letter, line end.
(I know this might not look simple if you're not familiar with the concept, but just read up on it and it will become clear very quickly. I recommend to read up on regexes in a Ruby context to know about all the quirks of Ruby regular expressions if you don't already.)
To use this regex inside your spec, I think you can use the following:
#zipcode.zipcode.should match(/\A[0-9]{4}[A-Z]{2}\z/)
To use it to actually validate this format inside your model, use this:
validates :zipcode, format: /\A[0-9]{4}[A-Z]{2}\z/

Related

rails validation with regex

I'm reading agile web development with rails 6.
In chapter 7, Task B: validation and unite testing
class Product < ApplicationRecord
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)\z}i,
}
what does the i mean in the end here?
It should mean that it's ending with .git or .jpg or .png
The i in your query tells the regex to match using a case insensitive match. There is nothing really unique to rails here so you may want to look into regexes in general to learn all the different terms you can use to modify your expression.
The expression %r{\.(gif|jpg|png)\z}i is equivalent to /\.(gif|jpg|png)\z/i
the \. means the period character
the | is an or as you stated
the \z is end of string with some caveats that you can read more about here: http://www.regular-expressions.info/anchors.html
and the i is incentive case matching
This means you would match 'test.jpg', 'test.JPg', 'test.JPG' or any permutation of those three characters in any case preceded by a period that occurs at the end of the string.
Here are the docs for regex formats in ruby specific:
https://ruby-doc.org/2.7.7/Regexp.html
And here is something where you can play with and learn regexes in general and try some expressions yourself:
https://regexr.com
short explain:
The "i" at the end of the regular expression is a modifier that makes the expression case-insensitive. This means that it will match both upper and lowercase letters in the image URL.

Specifying minimum length when using FFaker::Internet.user_name

I have a spec that keeps failing because FFaker::Internet.user_name generates a word that is less than 5 characters.
How do I specify a minimum length in this stmt:
username { FFaker::Internet.user_name }
String#ljust — Returns a copy of self of a given length, right-padded with a given other string.
username { FFaker::Internet.user_name.ljust(5,"12345") }
From what I see you try to use FFaker in your factory. Why overcomplicate things for your specs, when you could define sequence
sequence(:username) do |n|
"username-#{n}"
end
But the question is valid and you may have some legitimate needs to use ffaker, and there are many ways to do it. You can just concatenate username twice, why not?
username { FFaker.username + FFaker.username }
Or keep looking for a username that length is of minimal lenght:
username do
do
name = FFaker.username
while name.length < 5
name
end
Or monkeypatch ffaker and implement it yourself https://github.com/ffaker/ffaker/blob/0578f7fd31c9b485e9c6fa15f25b3eca724790fe/lib/ffaker/internet.rb#L43 + https://github.com/ffaker/ffaker/blob/0578f7fd31c9b485e9c6fa15f25b3eca724790fe/lib/ffaker/name.rb#L75
for example
class FFaker
def long_username(min_length = 5)
fetch_sample(FIRST_NAMES.select {|name| name.length >= min_lenght })
end
end
There're many ways you can achieve this, but if I had to do it, I'd do something like
(FFaker::Internet.user_name + '___')[0...5]
#=> "Lily_"
There are three underscores because after the quick lookup to the name list, I found the minimum length of first name is two characters so two plus three will always be at least five characters.
I'm only taking five character substring so as to not always have trailing underscore, but that's just my personal preference, you can use username plus three underscores and your test case will do fine.
You can't, but you could do FFaker::Name.name.join, this generates first name and middle name
You can also build it manually with regex using FFaker::String like so:
# 5 characters username, with first character being a letter
username { FFaker::String.from_regexp(/[a-zA-Z]\w{4}/) }
# random 5-10 characters username with first character being a letter
regex = Regexp.new("[a-zA-Z]\\w{#{Random.rand(4..9)}}")
username { FFaker::String.from_regexp(regex) }
Another idea is to add some random numbers to the end. This worked for me, was easy to implement, and looks fairly natural (since humans tend to do it when creating usernames in the wild).
E.g. this adds "1234" to the end of usernames:
"steve" + "1234"
and with Faker:
Faker::Internet.unique.user_name + "1234"
Note: if you want a random string (instead of "1234", try some of these approaches. However, it may not be necessary if you're already using the Faker .unique method as in the above example.

RegEx contain a combination of letters, numbers, and a special character

I'm finding a regular expression which adheres below rules.
Acceptance criteria: Password must contain a combination of letters, numbers, and at least a special character.`
Here is my Regex:
validates :password, presence: true,
format: { with: ^(?=[a-zA-Z0-9]*$)([^A-Za-z0-9])}
I am not all that great at regex, so any and all help is greatly appreciated!
You can use the following RegEx pattern
/^(?=.*\d)(?=.*([a-z]|[A-Z]))([\x20-\x7E]){8,}$/
Let's look at what it is doing:
(?=.*\d) shows that the string should contain atleast one integer.
(?=.*([a-z]|[A-Z])) shows that the string should contain atleast one alphabet either from downcase or upcase.
([\x20-\x7E]) shows that string can have special characters of ascii values 20 to 7E.
{8,} shows that string should be minimum of 8 characters long. While you have not mentioned it should be at least 8 characters long but it is good to have.
If you're unsure about the ASCII values, you can google it or you could use the following instead:
/^(?=.*\d)(?=.*([a-z]|[A-Z]))(?=.*[##$%^&+=]){8,}$/
As suggested in the comments, a better way can be:
/\A(?=.*\d)(?=.*([a-z]))(?=.*[##$%^&+=]){8,}\z/i
Here:
\A represents beginning of string.
\z represents end of string.
/i represents case in-sensitive mode.
P.S: I have not tested it yet. May be I'll test and update later if required.

Regex password validation for non-sequence data

I'm attempting to validate that my passwords may not contain any sequential characters such as "123" or "abcd" etc. I'm new to regex and i'm trying to do it by having the following code in my User model:
validate :password_complexity
def password_complexity
if password.present? and not password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d). /)
errors.add :password, "must include at least one lowercase letter, one uppercase letter, and one digit"
end
end
This is probably somewhat outside the bounds of regex. I would recommend looking into zxcvbn, which has also been ported into a ruby gem of the same name and even exists as a devise plugin. This will provide you with significantly more robust verification. You may also consider just inspecting the code for these projects, for inspiration, if you are determined to learn how one might implement something like this from scratch.
I agree that this isn't a job for a regex: maybe you could do it but it would be very complicated. Here's how i would do it.
def contains_sequential_characters?(string)
sequential = false
string.split("").each_with_index do |char,i|
if (string[i+1] == string[i]+1) && char =~ /[a-y0-8]/i
sequential = true
end
end
sequential
end
At the heart of this solution is that calling an array index on a string (eg "foo"[2]) will give you the ascii code of the character at that position. We only care about ascii codes that are next to each other between a-z and 0-9, which is why i'm also matching the first character against a-y (not z) and 0-8 (not 9).
You can use the below regex, which will accept a minimum of 13 digits and will not accept either sequential digits or sequential characters:
(?=.*?[0-9])(?!.*((12)|(23)|(34)|(45)|(56)|(67)|(78)|(90)|(01)))(?=.*?[a-zäöüß])(?!.*((ab)|(bc)|(cd)|(ef)|(fg)|(gh)|(hi)|(ij)|(jk)|(kl)|(lm)|(mn)|(no)|(op)|(pq)|(qr)|(rs)|(st)|(tu)|(uv)|(vw)|(wx)|(xy)|(yz)))(?=.*?[A-ZÄÖÜ])(?!.*((AB)|(BC)|(CD)|(EF)|(FG)|(GH)|(HI)|(IJ)|(JK)|(KL)|(LM)|(MN)|(NO)|(OP)|(PQ)|(QR)|(RS)|(ST)|(TU)|(UV)|(VW)|(WX)|(xy)|(yz))).{13,}

Conditional Regular Expression testing of a CSV

I am doing some client side validation in ASP.NET MVC and I found myself trying to do conditional validation on a set of items (ie, if the checkbox is checked then validate and visa versa). This was problematic, to say the least.
To get around this, I figured that I could "cheat" by having a hidden element that would contain all of the information for each set, thus the idea of a CSV string containing this information.
I already use a custom [HiddenRequired] attribute to validate if the hidden input contains a value, with success, but I thought as I will need to validate each piece of data in the csv, that a regular expression would solve this.
My regular expression work is extremely weak and after a good 2 hours I've almost given up.
This is an example of the csv string:
true,3,24,over,0.5
to explain:
true denotes if I should validate the rest. I need to conditionally switch in the regex using this
3 and 24 are integers and will only ever fall in the range 0-24.
over is a string and will either be over or under
0.5 is a decimal value, of unknown precision.
In the validation, all values should be present and at least of the correct type
Is there someone who can either provide such a regex or at least provide some hints, i'm really stuck!
Try this regex:
#"^(true,([01]?\d|2[0-4]),([01]?\d|2[0-4]),(over|under),\d+\.?\d+|false.*)$"
I'll try to explain it using comments. Feel free to ask if anything is unclear. =)
#"
^ # start of line
(
true, # literal true
([01]?\d # Either 0, 1, or nothing followed by a digit
| # or
2[0-4]), # 20 - 24
([01]?\d|2[0-4]), # again
(over|under), # over or under
\d+\.?\d+ # any number of digits, optional dot, any number of digits
| #... OR ...
false.* # false followed by anything
)
$ # end of line
");
I would probably use a Split(',') and validate elements of the resulting array instead of using a regex. Also you should watch out for the \, case (the comma is part of the value).

Resources