Adding a Phone Number to Users with Validations
Integrate a new column in the user database for phone numbers and update the RSpec tests.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

We are now going to implement the functionality for the SMS workflow we designed earlier.

We are not going to have tests here because for the most part, these tests can only check the rails framework. This is why there's a lot of opinions about using test driven development for implementing rake tasks. Personally, I'm not a big fan of these because I don't think the code tests our logic.

So, we are going to start with the basic code and refactor it later.

Before that, let's add a phone number for each user. To do that, the command is:

rails g migration add_phone_to_users phone:string

Next, migrate the database with the code

bundle exec rake db:migrate

We also have to make phone number a required field. So, search for User.create in the sublime editor and add the phone number field everywhere, just like the code in the seeds.rb file.

# db/seeds.rb

@user = User.create(email: "test@test.com",
                    password: "asdfasdf",
                    password_confirmation: "asdfasdf",
                    first_name: "Jon",
                    last_name: "Snow",
                    phone: "4322386131")

puts "1 User created"

AdminUser.create(email: "admin@test.com",
                  password: "asdfasdf",
                  password_confirmation: "asdfasdf",
                  first_name: "Admin",
                  last_name: "Name",
                  phone: "4322386131")

puts "1 Admin User created"

Make the same changes in the post_spec.rb and users.rb as well.

Next, we have to do some extensive validations. Twilio will throw an error if the phone number is in the format "555-555-5555", so we need it to match this format "5555555555", and also, we want to restrict it to just 10 characters. In addition, we want only numbers and no other characters.

So, our validations should cover these requirements:

Let's run rspec to ensure that everything is working fine. And it's not! If you see, we have 24 examples and all 24 failed! A quick look at the error messages show that all point to the same error, which is:

large

This is interesting because our SMS module has nothing to do with these tests.

Ok, the problem is a syntax error I made in a previous guide. Open the spec_helper.rb file and change the name of our module in line #11 from FakeSMS to FakeSms. So, it should now be:

# spec/spec_helper.rb


  config.before(:each) do
    stub_const("SmsTool", FakeSms)
  end

Run rspec again, and everything should pass.

Moving on, open user_spec.rb in spec/models and modify the test "cannot be created without first_name , last_name" to make phone numbers a required field.

Now, if you run rspec, it should fail. But, it doesn't!

Let's see why. I think three items maybe an overkill. So, let's isolate them like this:

# spec/models/user_spec.rb

it "cannot be created without first_name" do
  @user.first_name = nil
  expect(@user).to_not be_valid
end

it "cannot be created without last_name" do
  @user.last_name = nil
  expect(@user).to_not be_valid
end

it "cannot be created without phone" do
  @user.phone = nil
  expect(@user).to_not be_valid
end

Now, we have one failure, and that's exactly what we want. To fix this error, open user.rb and include phone in the list of validates_presence_of validators. So, it should look like this:

# app/models/user.rb

validates_presence_of :first_name, :last_name, :phone

Now, rspec should pass.

Next, let's update the administrate dashboard. Open user_dashboard.rb, and add the phone attribute to ATTRIBUTE_TYPES, SHOW_PAGE_ATTRIBUTES and FORM_ATTRIBUTES.

# app/dashboards/user_dashboard.rb

require "administrate/base_dashboard"

class UserDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    posts: Field::HasMany.with_options(searchable: false),
    id: Field::Number.with_options(searchable: false),
    email: Field::String.with_options(searchable: true),
    password: Field::String.with_options(searchable: false),
    sign_in_count: Field::Number.with_options(searchable: false),
    current_sign_in_at: Field::DateTime.with_options(searchable: false),
    last_sign_in_at: Field::DateTime.with_options(searchable: false),
    current_sign_in_ip: Field::String.with_options(searchable: false),
    last_sign_in_ip: Field::String.with_options(searchable: false),
    first_name: Field::String.with_options(searchable: false),
    last_name: Field::String.with_options(searchable: false),
    created_at: Field::DateTime.with_options(searchable: false),
    updated_at: Field::DateTime.with_options(searchable: false),
    type: Field::String.with_options(searchable: false),
    phone: Field::String.with_options(searchable: false),
  }.freeze

  COLLECTION_ATTRIBUTES = [
    :posts,
    :email,
    :type
  ].freeze

  SHOW_PAGE_ATTRIBUTES = [
    :posts,
    :email,
    :phone,
    :sign_in_count,
    :current_sign_in_at,
    :last_sign_in_at,
    :current_sign_in_ip,
    :last_sign_in_ip,
    :first_name,
    :last_name,
    :created_at,
    :updated_at,
    :type,
  ].freeze

  FORM_ATTRIBUTES = [
    :email,
    :password,
    :first_name,
    :last_name,
    :phone,
  ].freeze
end

Run rspec again to ensure we haven't broken any functionality.

Now, let's check in the browser. Sign in as an admin and create a new user. That's all good.

Next, open admin_user_dashboard.rb, and add the phone field, just like we did to the user_dashboard.

Check in the browser to see if you can create a new admin user, and with that working we can take a break.

Resources