Doug Steinberg
Doug Steinberg

Reputation: 1162

how to verify length and numericality of an atribute in rails with Rspec

I have a customer model with a first name, last name, and phone number. I want to let the user enter in the phone number in any format such as 555-555-5555 or (555)555-5555 or 555.555.5555

Here is my Customer model

class Customer < ActiveRecord::Base
  before_validation(on: :create) { format_phone_number }

  validates_presence_of :first_name, :last_name, :phone_number

  validates :phone_number, numericality: true, length: {minimum: 10}

  private

  def format_phone_number
    self.phone_number = phone_number.gsub(/[^0-9]/, "") if attribute_present?("phone_number")
  end
end

the format_phone_number method strips out any non-numeric characters before validation, then I want to validate it has a length is 10

and here is my spec

describe Customer do
  it { should validate_presence_of(:first_name)}
  it { should validate_presence_of(:last_name)}
  it { should validate_presence_of(:phone_number)}
  it { should ensure_length_of(:phone_number).is_at_least(10) }

  describe "phone_number" do
    it "should remove non-numeric characters" do
      bob = Fabricate(:customer, first_name: "Bob", last_name: "Smith", phone_number: "555-777-8888" )
      expect(bob.phone_number).to eq('5557778888')
    end
  end
end 

When I run this I get this error

Failure/Error: it { should ensure_length_of(:phone_number).is_at_least(10) }
       Did not expect errors to include "is too short (minimum is 10 characters)" when phone_number is set to "xxxxxxxxxx", got error: is too short (minimum is 10 characters)

So it seems like Rspec is trying to test the length with "xxxxxxxxxx" , and my method is stripping all the x's before the object gets saved. What would be a better way to test or implement this?

Upvotes: 2

Views: 1520

Answers (1)

Pete
Pete

Reputation: 2246

This is probably occurring because the format_phone_number callback is only triggered just before validation. While I haven't use the Fabrication gem, the documentation indicates it initializes the ActiveRecord object but does not call save or valid?. Therefore the before_validation callback is not triggered. Try adding valid? before the rspec assertion:

it "should remove non-numeric characters" do
  bob = Fabricate(:customer, first_name: "Bob", last_name: "Smith", phone_number: "555-777-8888" )
  bob.valid?
  expect(bob.phone_number).to eq('5557778888')
end

Alternatively you can use the after_initialize ActiveRecord callback to trigger the formatting as soon as a Customer object is built:

class Customer < ActiveRecord::Base
  #...
  after_initialize :format_phone_number

  #...
end

Upvotes: 1

Related Questions