Here.
For the sake of single responsibility, and because it'll make the narrative easier, I'd suggest creating a lib/twilio_module.rb
where you store your Twilio logic. Then you can either include it in an object, or call it verbosely using something like TwilioModule::twilio_client
. (I do the first method because it's prettier, but it's not always obvious where these methods are magically coming from).
Your twilio module might look like:
module TwilioModule
def twilio_client
Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
end
def avilable_numbers_in_area_code(area_code)
twilio_client.account.available_phone_numbers.get('US').local.list(:area_code => area_code)
end
def available_numbers_anywhere
twilio_client.account.available_phone_numbers.get('US').local.list
end
def available_number(area_code)
numbers = available_numbers_in_area_code(area_code)
numbers.present? ? numbers.first : available_numbers_anywhere.first
end
def buy_number(number)
client.account.incoming_phone_numbers.create(:phone_number => number)
end
def buy_an_available_number(area_code)
number = available_number(area_code)
buy_number(number) #returns a twilio_number object
end
def update_application_sids(phone_number)
phone_number.update(
:voice_application_sid => ENV['ANONYMOUS_APPLICATION_SID'],
:sms_application_sid => ENV['ANONYMOUS_APPLICATION_SID']
)
end
end
You will need to create a file at config/initializers/modules.rb
that simply says:
require File.join(Rails.root, "lib/twilio_module.rb")
This tells Rails to load the module when it starts up, which it won't do otherwise.
With all this reusable logic in place, your provision_phone_number becomes:
include TwilioModule
def provision_phone_number
begin
anon_number = buy_an_available_number(self.host.area_code)
update_application_sids(anon_number)
self.update(phone_number: anon_number.phone_number)
rescue Exception => e
puts "ERROR: #{e.message}"
end
end
I haven't tested any of this code, so I'm sure it has errors. I'm also not sure that including a module is the best practice way of doing this so you might want to run it past Phil. But I suspect that extracting the Twilio logic into macro-like methods will make it easier to explain what's going on.