floere/phony — Issue #27: Phony gets crazy, when phone number == nil
Author: tmaier
Created: 2011-10-12 00:14:40+00:00
State: open

This is what I wanted to do in my model:

```ruby
def phone_number=(phone_number)
write_attribute(:phone_number, Phony.normalize(phone_number))
end

def phone_number
Phony.format(read_attribute(:phone_number))
end
```
(I know, a representer/decorator would not be bad.)

This is my spec for this feature:

```ruby
require 'spec_helper'

describe Phone do
describe "phone number normalization and formation" do
let(:person) {Fabricate.build(:person)}

it "using %phone_number=" do
person.phones = []
person.phones << Phone.new
person.phones.first.phone_number = "+491717584135"
person.phones.first.phone_number.should eq("+49 171 758 4135")
person.phones.first[:phone_number].should eq("491717584135")
end

it "using %attributes" do
hash = {"phones_attributes"=>[{
"_id"=>person.phones.first.id,
"phone_number"=>"+491717584135"
}]}
person.attributes = hash
person.should be_valid
person.phones.first.phone_number.should eq("+49 171 758 4135")
person.phones.first[:phone_number].should eq("491717584135")
end

it "using %[]=" do
person.phones.first[:phone_number] = "+491717584135"
person.should be_valid
person.phones.first.phone_number.should eq("+49 171 758 4135")
end

it "does not fail if phone_number is nil" do
person.phones.first.phone_number = nil
person.should be_valid
person.phones.first.phone_number.should be_nil

person.phones.first.phone_number = "+491717584135"

person.phones.first[:phone_number] = nil
person.should be_valid
person.phones.first.phone_number.should be_nil
end
end
end
```

when I run this spec, I get the following error messages:

```terminal
Phone
phone number normalization and formation
using %phone_number=
using %attributes
using %[]= (FAILED - 1)
does not fail if phone_number is nil (FAILED - 2)

Failures:

1) Phone phone number normalization and formation using %[]=
Failure/Error: person.should be_valid
NoMethodError:
undefined method `split' for 1:Fixnum
# ./app/models/phone.rb:45:in `phone_number'
# ./spec/models/phone_spec.rb:33:in `block (3 levels) in '

2) Phone phone number normalization and formation does not fail if phone_number is nil
Failure/Error: person.phones.first.phone_number = nil
TypeError:
can't dup NilClass
# ./app/models/phone.rb:41:in `phone_number='
# ./spec/models/phone_spec.rb:38:in `block (3 levels) in '

Finished in 0.23927 seconds
4 examples, 2 failures

Failed examples:

rspec ./spec/models/phone_spec.rb:31 # Phone phone number normalization and formation using %[]=
rspec ./spec/models/phone_spec.rb:37 # Phone phone number normalization and formation does not fail if phone_number is nil
```

In the end, I came up with the following to get this spec running.

```ruby
def phone_number=(phone_number)
value = Phony.normalize(phone_number) unless phone_number.nil?
write_attribute(:phone_number, value)
end

def phone_number
@phone_number_loop ||= 0
Phony.format(read_attribute(:phone_number)) unless read_attribute(:phone_number).nil?
rescue NoMethodError => error
@phone_number_loop += 1
self.phone_number = self[:phone_number]
if @phone_number_loop == 1
phone_number
else
raise error
end
end
```

It would be nice, if

* `Phony.normalize` could handle nil
* `Phony.format` could also handle nil
* `Phony.format` would run a string through Phony.normalize when the string was not normalized before, instead of failing.
* `Phony` would convert anything it gets to String before processing it to avoid failing when it is not necessary.

Thanks!

Tobias