Skip to content
Felix Schäfer edited this page Jul 7, 2017 · 5 revisions

My example use mongoid and custom sms provider. For my case I had to make it more in JS with manual validations so this may not be for you. Take a closer look to Model and Controller on how active_model_otp is used.

Model

require "active_model_otp"
class User
  include Mongoid::Document
  ...
  include ActiveModel::OneTimePassword 
  ...
  has_one_time_password
  ...
  field :email
  field :otp_secret_key 

Controller

def check_verification_code
  data = {:result => false}
  if current_user.authenticate_otp(params[:verification_code], drift: 200) #drift enough for old users 
    data = {:result => true}
    session[:mobile_verified] = true
  end
  respond_to do |format|
    format.json  { render :json => data} 
  end
end
       
def sendverification
   data = {:result => false} 
   phone = validate_phone(params[:verification_phone])
   if phone.present?
     sms = Sms.new       
     if sms.send_sms([phone],APP_CONFIG.sms_from, t('verification_message') + current_user.otp_code.to_s)
       data = {:result => true} 
     end
  end
  respond_to do |format|
    format.json  { render :json => data} 
  end
end
     
def create 
  ...
  if session[:mobile_verified] = true
    @provider.mobile_verified = true
    @provider.business_phone = validate_phone( params[:provider][:business_phone])
    session[:mobile_verified] = false
  else
  ...

View (in HAML)

= bootstrap_form_for @provider, id: @provider.id,  validate: true  do |f|
  .span{style: 'text-align: center'}
    %h4= t('.provider_exp')
    %h5= t('.provider_exp1')
    #phone_details
      = f.label :mobile_phone, class: 'control-label', id: 'verify_phone_label'
      = f.default_tag :text_field, :verification_phone, placeholder: '05XX XXXXXXX', id: 'verification_phone' ,:class => "{mask:'(0569) 9999999'}", :alt=> "(0569) 9999999'"
      = button_to t('.send_code'), "#", :id=> 'sendverification', :class=> 'btn btn-medium btn-success'
      = f.label :error_mobile_label, class: 'control-label', id: 'error_mobile_label'
    %hr
    #verification_details
      = f.label :info_label, class: 'control-label', id: 'verify_code_label' , style:"display:none"
      = f.default_tag :text_field, :verification_code, placeholder: 'XXXXXX', id: 'verification_code' ,:class => "{mask:'999999'}", :alt=> "999999'"
      = f.label :error_label, class: 'control-label', id: 'error_code_label'
      = f.label :success_label, class: 'control-label', id: 'success_code_label'

Scripts (in Coffescript)

$("#verification_code").bind "keyup", ->
  if $(this).val().length is 6 #second clientside validation
    data = undefined
    $.ajax
      type: "POST"
      url: "/check_verification_code"
      data: "verification_code=" + $("#verification_code").val()
      success: (data) ->
        if data.result is true
          $("#provider_business_phone").val($("#verification_phone").val())
          clearInterval(interval)
          $("#error_code_label").hide()
          $("#success_code_label").show()
          $("#verification_code").prop "disabled", true
          $("#provider_submit").prop "value", I18n.t "shared.navbar.pleasewait"
          $("#providerform").submit() # provider gets mobile_verified inside
          return
        else
          $("#error_code_label").text I18n.t('shared.navbar.error_in_code').show()
        return
      error: (data) ->
        $("#error_code_label").text  I18n.t('shared.navbar.problem_sending_request').show()
        return
  else
    $("#error_code_label").hide()
    $("#success_code_label").hide()
    return
  return

interval = undefined
$("#sendverification").click ->
  if $("#verification_phone").val().length is 14 #second clientside vald(before svrside)
    time = 30000 #OTP default wait time
    seconds = Math.ceil(time / 1000)
    $(this).each ->
      disabled_elem = $(this)
      $("#verification_phone").prop "disabled", true
      disabled_elem.prop "disabled", true
      new_text =  I18n.t('shared.navbar.send_code_again')
      disabled_elem.val new_text + " (" + seconds + ")"
      interval = setInterval(->
        disabled_elem.val new_text + " (" + --seconds + ")"
        if seconds is 0
          $("#verification_phone").prop "disabled", false
          disabled_elem.prop "disabled", false
          disabled_elem.val new_text
          clearInterval interval
        return
      , 1000)
      return
    $.ajax
      data: "verification_phone=" + $("#verification_phone").val()
      type: "get"
      url: "/sendverification"
      success: (data) ->
        if data.result is true
          $("#verification_code").show()
          $("#verify_code_label").show()
          $("#error_mobile_label").hide()
          $("#error_code_label").hide()
          $("#verification_code").val ''
          $("#verification_code").focus()
          return
        else
          $("#error_mobile_label").text I18n.t('shared.navbar.problem_sending_sms').show()
          return
      error: (data) ->
        $("#error_mobile_label").text  I18n.t('shared.navbar.problem_sending_request').show()
        return
  return false