Validate phone-number format in Rails 4 - REGEX - ruby-on-rails

I'm working on a small project where the user should type the phone numbers, so I would like to validate that information using the "ClientSideValidations" gem.
validates_format_of :telcasa, :celular, :tel_flia, :tel_trab, :tel_ref_2, :tel_ref_1,
length: { in: 10 },
:with => /\A(\d{10}|\(?\d{3}\)?[-. ]\d{3}[-.]\d{4})\z/,
:message => "Formato invalido"
But, for the region where this project is going to be used I have to validate the three first numbers of the phone that correspond to the area code ("809"/"829"/"849"). How can I validate that the user correctly typed the phone number with one of the three area codes?

Change /\A(\d{10}|\(?\d{3}\)?[-. ]\d{3}[-.]\d{4})\z/ to:
/\A(\(?(809|829|849)\)?[-. ]\d{3}[-.]\d{4})\z/
I took the liberty of dropping the part where you are matching any ten digit number - not sure why it was there or how it should be used in your context.

You can write some custom validation
validate do
valid_phone_codes = [ "007", "042", ...]
valid_phone_codes.each do |valid_code|
# Also handle optional parenthesis
return true if self.phone_number.starts_with?(valid_code, "(#{valid_code})")
end
errors.add(:phone_numbers, "Must start with a valid country code (one of #{valid_phone_codes.join(', ')}")
false
end
Or if you prefer, you can declare this code in a function def valid_country_codes, and then add a line
validate :valid_country_codes

Related

Attributes of the helper validates_length_of

Is there any attribute in the helper validates_length_of that makes the field tested accept only one of 2 fixed sizes, such as 10 and 12?
In case, if the user sent the value 11 will not be accepted.
I already researched some attributes, but found nothing
The code I tried to run was this:
validates_length_of :field, is: 14 || 18
The code snippet does not produce an error, but only takes the first value
In your code || is ruby boolean or operator, it returns first argument if it is non-falsey and the second otherwise.
Length validator does not accept array for is in current rails, so for your case you'll have to write a custom validator:
validate :length_of_my_field
private def length_of_my_field
errors.add(:field, "should have length of 12 or 18") unless [12, 18].include?(field.size)
end

Ruby: Verifying if the given user input is a number

I want to check if the variable which is basically a user input is a 10 digit phone number or not.
There are 2 sets of validations:
- If num is less than 10 digit then prompt a msg
- if num is a string instead rather than integer
#phone = params[:phone_num]
puts "phone_num: #{#phone}"
if #phone.is_a? Integer
puts "phone_num is int"
if #phone.to_s.length == 10
puts "10 digit"
perform(#phone)
#output = "Valid Number, will receive a call"
end
else
puts "Wont be calling"
#output = "The number is invalid"
end
The output that I get is always The number is invalid no matter what I enter in text box. There are many stack overflow answering dealing with different questions but wondering why my code didn't work.
There is standard validation (length) & (numericality) for this:
#app/models/user.rb
class User < ActiveRecord::Base
validates :phone_num, length: { is: 10 }, numericality: { only_integer: true }
end
This type of validation belongs in the model.
Notes
Your controller will look as follows:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
#user = User.new user_params
#user.save #-> validations handled by model
end
end
There's a principle called fat model, skinny controller - you should put "data" logic in your model.
The reason for this is to remove inefficient code from the controller.
It gives you the ability to delegate much of your logic to the Rails core helpers (validations for example), instead of calling your own mass of code in the front-end (like you're doing).
Each time you run a Rails app, the various classes (controller & model) are loaded into memory. Along with all of the Rails classes (ActiveRecord etc), your controllers & models have to be loaded, too.
Any extra code causes causes bloat, making your application buggy & unusable. The best developers know when to use their own code, and when to delegate to Rails. This example is a perfect demonstration of when to delegate.
The output that I get is always The number is invalid no matter what I
enter in text box.
The reason why your code always falls back to else part because the values that are coming from the params will always be strings. So the value of params[:phone_num] is a string. So your code is failing here if #phone.is_a? Integer. Instead you need change it to params[:phone_num].to_i
#phone = params[:phone_num].to_i
puts "phone_num: #{#phone}"
if #phone.is_a? Integer
puts "phone_num is int"
if #phone.to_s.length == 10
puts "10 digit"
perform(#phone)
#output = "Valid Number, will receive a call"
end
else
puts "Wont be calling"
#output = "The number is invalid"
end
Note:
Yes. This is poor way to perform validations. I'm just answering the OP's question.
Take a look at this - A comprehensive regex for phone number validation - how to determine a string looks like a phone number. There's a very complex regex, because people have various forms for entering phone numbers!
I personally don't like super complex regexes, but it's pretty much what they were invented for. So this is when you want to figure out what sorts of forms are acceptable, write some tests, and make your code pass to your acceptance based on the massive link above!
edit: your code is wrong in a bunch of places; params are already a string, so try this! Remember your nested if/else/end, too.
#phone = params[:phone_num]
if #phone =~ /\A\d+\Z/ # replace with better regex
# this just means "string is all numbers"
puts "phone_num is int"
if #phone.length == 10
puts "10 digit"
perform(#phone)
#output = "Valid Number, will receive a call"
else
puts "Number length wrong, #{#phone.length}"
end
else
puts "Wont be calling, not a number: #{#phone.inspect}"
#output = "The number is invalid"
end

Ruby on Rails - Validations and Before Filter method to substitute User Inputted Values

In my Ruby on Rails app, I have a sign-up form, where users have to enter some data. I have strict validations that only allow entered values that are members of an array. This isn't part of my app, but it uses the same concept I want to apply.
Say I wanted to have a field where a user entered a superhero name. My validations would have an array like so.
SUPERHEROES = ['Batman', 'Superman', 'Captain America', 'Wonder Woman', 'Spiderman']
validates_inclusion_of :superhero, :in => SUPERHEROES
If a user entered Clark Kent, for example, the validations would fail. Given I created a new array.
ALIASES = ['Bruce Wayne', 'Clark Kent', 'Steven Rogers', 'Princess Diana', 'Peter Parker']
I'd like before the form is submitted (update action) for the values in the ALIASES array to be converted into the SUPERHEROES array.
I was thinking something like this could work.
def alias_to_superhero
ALIASES.each_do |alias|
i = 0
while i < SUPERHEROES.length
alias.gsub(alias, "#{SUPERHEROES[i]}")
i++
end
end
end
And then at the top of my validations final I could have a line like this
before_update: alias_to_superhero
Any suggestions?
You can validate that superhero contains the hero or the alias name of an superhero. But after validation before save you replace aliases with the matching hero name. The benefit of replacing the alias with the hero name after validation is that you keep the users input untouched unless all validations succeed.
validates_inclusion_of :superhero, :in => SUPERHEROES + ALIAS
before_save :replace_alias_with_hero_name
private
def replace_alias_with_hero_name
if ALIAS.include?(superhero)
self.superhero = SUPERHEROES[ALIAS.find_index(superhero)]
end
end
This solution only work when both arrays have the same size and the hero names and aliases are at the same position in the array. A more flexable version would perhaps operate on a hash like this:
HEROS => { 'SUPERMAN' => ['Clark Kent', 'C. Kent' ... ] ... }
You will have to use before_validation callback instead of before_update
before_validation: alias_to_superhero
Also you can check directly against inclusion of ALIASES or have a join array of both ALIASES and SUPERHEROS for validity.

Rails Specifying the order of validations

I have a validator class that i am writing that has three validations, that are run when calling MyVariableName.valid?
validates_length_of :id_number, :is => 13, :message => "A SA ID has to be 13 digits long"
validates_format_of :id_number, :with => /^[0-9]+$/, :message => "A SA ID cannot have any symbols or letters"
validate :sa_id_validator
The third one is a custom validator. The thing is that my validator sa_id_validator requires that the data that is passed in is a 13 digit number, or I will get errors. How can I make sure that the validate :sa_id_validator is only considered after the first two have run?
Sorry if this is a very simple question I have tried figuring this out all of yesterday afternoon.
Note: this validator has to run over a couple thousand entries and is also run on a spreadsheet upload so I need it to be fast..
I saw a way of doing this but it potentially runs the validations twice, which in my case would be bad.
EDIT:
my custom validator looks like this
def sa_id_validator
#note this is specific to South African id's
id_makeup = /(\d{6})(\d{4})(\d{1})(\d{1})(\d{1})/.match(#id_number)
birthdate = /(\d{2})(\d{2})(\d{2})/.match(id_makeup[1])
citizenship = id_makeup[3]
variable = id_makeup[4]
validator_key = id_makeup[5]
birthdate_validator(birthdate) && citizenship_validator(citizenship) && variable_validator(variable) && id_algorithm(id_makeup[0], validator_key)
end
private
def birthdate_validator(birthdate)
Date.valid_date?(birthdate[1].to_i,birthdate[2].to_i,birthdate[3].to_i)
end
def citizenship_validator(citizenship)
/[0]|[1]/.match(citizenship)
end
def variable_validator(variable)
/[8]|[9]/.match(variable)
end
def id_algorithm(id_num, validator_key)
odd_numbers = digits_at_odd_positions
even_numbers = digits_at_even_positions
# step1: the sum off all the digits in odd positions excluding the last digit.
odd_numbers.pop
a = odd_numbers.inject {|sum, x| sum + x}
# step2: concate all the digits in the even positions.
b = even_numbers.join.to_i
# step3: multiply step2 by 2 then add all the numbers in the result together
b_multiplied = (b*2)
b_multiplied_array = b_multiplied.to_s.split('')
int_array = b_multiplied_array.collect{|i| i.to_i}
c = int_array.inject {|sum, x| sum + x}
# step4: add the result from step 1 and 3 together
d = a + c
# step5: the last digit of the id must equal the result of step 4 mod 10, subtracted from 10
return false unless
validator_key == 10 - (d % 10)
end
def digits_at_odd_positions
id_num_as_array.values_at(*id_num_as_array.each_index.select(&:even?))
end
def digits_at_even_positions
id_num_as_array.values_at(*id_num_as_array.each_index.select(&:odd?))
end
def id_num_as_array
id_number.split('').map(&:to_i)
end
end
if i add the :calculations_ok => true attribute to my validation, and then pass in a 12 digit number instead i get this error:
i.valid?
NoMethodError: undefined method `[]' for nil:NilClass
from /home/ruberto/work/toolkit_3/toolkit/lib/id_validator.rb:17:in `sa_id_validator'
so you can see its getting to the custom validation even though it should have failed the validates_length_of :id_number??
I am not quite sure but i have read at some blog that Rails always runs all validations even if the first one is invalid.
What you can do is to make your custom method in such a way that it would become flexible or bouncy in such a way that i would handle all the cases.
This answer would definitely help you.
Hope it would answer your question

Ruby on Rails - Currency : commas causing an issue

Looking on SO, I see that the preferred way to currency using RoR is using decimal(8,2) and to output them using number_to_currency();
I can get my numbers out of the DB, but I'm having issues on getting them in.
Inside my update action I have the following line:
if #non_labor_expense.update_attributes(params[:non_labor_expense])
puts YAML::dump(params)
The dump of params shows the correct value. xx,yyy.zz , but what gets stored in the DB is only xx.00
What do I need to do in order to take into account that there may be commas and a user may not enter .zz (the cents). Some regex and for comma? how would you handle the decimal if it were .2 versus .20 .
There has to be a builtin or at least a better way.
My Migration (I don't know if this helps):
class ChangeExpenseToDec < ActiveRecord::Migration
def self.up
change_column :non_labor_expenses, :amount, :decimal, :precision => 8, :scale => 2
end
def self.down
change_column :non_labor_expenses, :amount, :integer
end
end
I tried Daniel's before_validation idea and I just couldn't get it to work. It seemed that the by the time I get to the before_validation the input has already been converted. The solution I went with was to override the method for the column, and strip the commas there:
def profit=(num)
num.gsub!(',','') if num.is_a?(String)
self[:profit] = num
end
It might depend on what DBMS you're using, but as far as I know, decimal fields won't accept commas (at least not as separators; there might be a way to have the database accept a comma as a decimal point rather than a period). What you will have to do is remove the commas from your numbers (in a before_save or before_validation filter, perhaps), and then when you display the number, add the commas back in.
before_validation :strip_commas_from_non_labor_expense
def strip_commas_from_non_labor_expense
self.non_labor_expense = self.non_labor_expense.to_s.gsub(/,/, '').to_f
end
Then use number_to_currency when you want to display the expense amount formatted with comma separated groups and two decimal places, as you mentioned:
<%
non_labor_expense = ... # get value from your model
puts number_to_currency(non_labor_expense, :precision => 2, :separator => ',')
%>
Checkout the delocalize gem:
http://github.com/clemens/delocalize
Here you can find a code snippet that will make any decimal column accept values with the comma as decimal separator:
http://gem-session.com/2010/03/how-to-use-the-comma-as-decimal-separator-in-rails-activerecord-columns-and-text-fields

Resources