Kenny Zhang
Kenny Zhang

Reputation: 63

How do I use set up Twilio in my application to automatically send a text to a number?

I have a Ruby on Rails application where users create a "Reminder" and once it is created and saved to the database (POSTGRESQL), the number which the User inputed on making the reminder should be texted a message (by creating a message using Twilio's REST API). My Twilio credentials are correct and my environment variables are set properly in the application.

The reminder is evidently being created (seen after rails s in the console) but I am not receiving an SMS at all, and I am wondering if it has to do with the syntax in my reminder.rb:

class Reminder < ActiveRecord::Base
  validates :title, presence: true
  validates :phone_number, presence: true
  validates :time, presence: true
  belongs_to :user

  after_create :send_text_message

  @@SEND_TEXT_MESSAGE_TIME = 5.minutes

  def send_text_message
    @twilio_phone_number = ENV['TWILIO_PHONE_NUMBER']
    @twilio_client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
    # %k: 24hr time, %M: minute, %p: AM/PM, %b: e.g. "Jan", %d: zero padded day of the month e.g. "01"
    numba = "+1"+self.phone_number
    time_str = ((self.time).localtime).strftime("%k:%M%p on %b. %d")
    body = "Hi. Just a reminder that #{self.title} is coming up at #{time_str}."
    message = @twilio_client.account.sms.messages.create(
      :from => @twilio_phone_number,
      :to => numba,
      :body => body,
      )
    puts message
  end

  def when_to_run
    time - @@SEND_TEXT_MESSAGE_TIME
  end

  handle_asynchronously :send_text_message, :run_at => Proc.new { |i| i.when_to_run }
end

The form that the user submits is here:

<%= simple_form_for [@user,@reminder] do |f| %>
  <% if @reminder.errors.any? %>
    <div id="error_expl" class="panel panel-danger">
      <div class="panel-heading">
        <h3 class="panel-title"><%= pluralize(@reminder.errors.count, "error") %> prohibited this reminder from being saved:</h3>
      </div>
      <div class="panel-body">
        <ul>
        <% @reminder.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
        </ul>
      </div>
    </div>
  <% end %>

  <%= f.input :title , class: "form-control"%>
  <%= f.input :phone_number, class: "form-control", input_html: { value: current_user.phone_number } %>
  <%= f.input :time, class: "form-control" %>
  <%= f.submit nil, :class => "btn btn-primary" %>
  <%= link_to 'Cancel', user_reminders_path(current_user), class: "btn btn-danger" %>
<% end %>

and finally, my reminders_controller.rb:

class RemindersController < ApplicationController

  def index
    @user = User.find_by_id params[:user_id]
    @reminders = @user.reminders
    if @reminders.length == 0
      flash[:notice] = 'You have no reminders scheduled. Create one now to get started.'
    end
  end

  def new
    @user = User.find_by_id params[:user_id]
    @reminder = @user.reminders.new
  end

  def create
    # Time.zone = reminder_params[:time_zone]
    @user = current_user
    @reminder = @user.reminders.build reminder_params

    respond_to do |format|
      if @reminder.save
        flash[:success] = 'Reminder was created successfully!'
        format.html {
          redirect_to user_reminders_path
        }
      else
        flash.now[:notice] = 'Reminder could not be created. Please try again.'
        format.html {
          render :new 
        }
        format.json {
          render json: @reminder.errors.full_messages
        }
      end
    end
  end

  def show
    @reminder = Reminder.find(params[:id])
  end

  def edit
    @reminder = Reminder.find(params[:id])
  end

  def update
   @reminder = Reminder.find(params[:id])
   @reminder.user_id = current_user.id
    respond_to do |format|
      if @reminder.update_attributes(reminder_params)
        flash[:success] = 'Reminder has been successfully updated.'
        format.html {
          redirect_to user_reminders_path(current_user)
        }
        format.json {
          render json: @reminder
        }
      else
        flash[:error] = 'Reminder could not be updated.'
        format.html {
          redirect_to edit_reminder_path
        }
        format.json {
          render json: @reminder.errors.full_messages
        }
      end
    end
  end

  def destroy
    @reminder = Reminder.find(params[:id])
    @reminder.destroy
    respond_to do |format|
      format.html { redirect_to user_reminders_path(current_user.id), notice: 'reminder was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

  def reminder_params
    params.require(:reminder).permit(:title, :time, :phone_number)
  end
end

Am I missing something? I am new to rails and am more used to the MEAN stack, so I am thinking it is maybe my use of variables and the self keyword that are messing things up for me. I am looking for advice on anything I can do or fix to make the Message resource from Twilio's REST API send a text to a number that I input.

Upvotes: 0

Views: 210

Answers (1)

philnash
philnash

Reputation: 73029

Twilio developer evangelist here.

@ajporterfield makes a couple of good suggestions, make sure you're using live, not test, credentials and try making this work without delaying the method.

I have a couple of other questions. Are you running the delayed job process to process the jobs?

Have you upgraded your account? If you are still using a free Twilio account you will need to make sure that all the numbers you send messages to are verified in your account. Once you upgrade your account you can send messages to any number.

Finally, one suggestion: you are currently calling @twilio_client.account.sms.messages.create. The sms.messages endpoint in the API is actually deprecated right now so it is better to just call messages. Also, as a convenience, if you are using the main account, you don't need to call account either. So you can actually shorten that line to: @twilio_client.messages.create and it will work better and look tidier.

Let me know if this helps at all.

Upvotes: 1

Related Questions