Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails: Validating and changing a phone number

I have a simple phone form <%= f.text_field :phone %> right now. :phone is an integer type, so this requires that whatever the user enters into the form must be something like 5551234 instead of the more standard way of 555-1234 How can I allow the user to enter in a USA phone number like their accustomed to? I understand that I can use validates_format_of to validate it, but once I validate it, how can I format the number and insert the phone number into the DB as an integer?

like image 515
Reti Avatar asked Jul 30 '10 00:07

Reti


2 Answers

ActiveRecord automatically typecasts input based on the databases column type. When Ruby casts a string to an integer it drops everything after the first non-numeric character, 123-456-7890 will become 123. This is done before the field is available in the model so the solutions given so far will not work. You need to overwrite the default write accessor!

The ActiveRecord::Base docs mentions two ways to overwrite the default write accessor (field_name)= in the model so you can process the input removing the non-digits before it needs to be typecast. There are at least three variations:

(1) Overwrite the accessor and use write_attribute to store the result in the database:

def phone=(value)
  value.gsub!(/\D/, '') if value.is_a?(String)
  write_attribute(:phone, value.to_i)
end

(2) Or use the hash notation:

def phone=(num)
  num.gsub!(/\D/, '') if num.is_a?(String)
  self[:phone] = num.to_i
end

(3) Or (in the latest versions of ActiveRecord) just call super as if it were a normal (non-dynamic) method (not shown in docs but works):

def phone=(num)
  num.gsub!(/\D/, '') if num.is_a?(String)
  super(num)
end

This is useful in a number of situations such as numbers with commas and works great with forms that supply a formatted version of the previous field value such as in an edit form or after an error in a new/create form:

<%= f.text_field :phone, number_to_phone(@model_data.phone) %>

This way you can show the user formatted data (i.e. as String) but still store an integer in the database.

One last tip on MySQL: You need to use a BigInt to store a phone number otherwise you will see a lot of (214) 748-3647 phone numbers in your database as 2,147,483,647 is the max value of a normal MySQL integer - int(11) - obtained form :integer in a migration. A BigInt in MySQL is obtained by setting :limit to 8 as in this migration line:

change_column :model_name, :phone, :integer, :limit => 8

This will give you a bigint(20) in your table which can handle numbers up to 9,223,372,036,854,775,807 which should be sufficient for any phone number.

like image 118
Niels Avatar answered Oct 06 '22 00:10

Niels


phone.gsub(/\D/, '')

should do the trick. It removes non-digit chars.

like image 22
Mark Thomas Avatar answered Oct 06 '22 00:10

Mark Thomas