daddyz / phonelib

Ruby gem for phone validation and formatting using google libphonenumber library data
MIT License
1.06k stars 130 forks source link

country_specifier: doesn't work - Validates every country #298

Closed geniusClint closed 6 months ago

geniusClint commented 7 months ago

Rails 7.1.2 Ruby 3.2.0

My Phone Model has a country_code that is the 2 digit country code from gem country_code_select. I have a dropdown (select) box for the user to specify the country the phone belongs to. The select is populated on the form as :country_code

I tried every combination of:

validates :number, phone: {country_specifier: :country_code}

and also

validates :number, phone: {country_specifier: -> phone { country_code} }

I could send a valid MX phone number and it validates it as US or Canada or any other country, as well as MX. I could send a valid US phone number and specify it as MX and it would validate.

I ended up creating a custom validator in my model:

class Phone < ApplicationRecord validate :should_be_valid_for_country

private def should_be_valid_for_country valid = Phonelib.valid_for_country? number, country_code errors.add(:number, "is not valid for country selected") unless valid end

This solved my problem, but I am pretty sure I followed the directions for the build in country validator and it didn't work...

nflorentin commented 6 months ago

Did you try this ? It is working for me (same version of Rails).

validates :number, phone: {country_specifier: -> your_model { your_model.country_code} }
geniusClint commented 6 months ago

I just tried with: validates :number, phone: { country_specifier: -> phone { phone.country_code } }

Trying to save the number +12105352100 as: USA is valid (as expected) Canada is INVALID (as expected) Mexico is VALID (Not expected) Albania is VALID (Not expected) ...

nflorentin commented 6 months ago
Phonelib.parse('+12105352100', 'MX').national
=> "(210) 535-2100"

So I think that Phonelib is somehow ignoring the +1 validating your phone number.

The syntax is now correct, because in a ruby console Phonelib.parse('+12105352100', 'MX').valid? returns true.

The validator seems permissive....

I never used phonelib until today so I'm total newbie with it but I was testing validations too so I found your issue.

nflorentin commented 6 months ago

Just tested your number on libphonenumber demo and it seems that your result is expected, look https://libphonenumber.appspot.com/phonenumberparser?number=%2B12105352100&country=MX

Validations
Result from isPossibleNumber() true
Result from isValidNumber() true
Result from isValidNumberForRegion() false

So it is the expected behaviour, your US number is a valid number if you make your call from Mexico.

nflorentin commented 6 months ago

Ok I just understood.

Phonelib.parse('+12105352100', 'MX').valid?
=> true
Phonelib.valid_for_country? '+12105352100', 'MX'
=> false

The validator is equivalent to the first line, not the second one,

So you should use valid_for_country? for your use case.

geniusClint commented 6 months ago

Which makes sense as to why my custom validator works as expected.

validate :should_be_valid_for_country

private def should_be_valid_for_country valid = Phonelib.valid_for_country? number, country_code errors.add(:number, "is not valid for country selected") unless valid end

daddyz commented 6 months ago

@geniusClint when phone number starts with "+" phonelib switches country, there is configuration parameter that allows to disable this behaviour:

Phonelib.ignore_plus = true