まずTwilioでアカウント登録をしてください。
www.twilio.com
アカウントの登録は以下の手順でお願いします。
mrradiology.hatenablog.jp
記述追加 GemFile
86行目に「gem 'twilio-ruby', '~> 4.11.1'」の記述追加
source 'https://rubygems.org' git_source(:github) do |repo_name| repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 5.0.7', '>= 5.0.7.1' # Use postgresql as the database for Active Record gem 'pg', '>= 0.18', '< 2.0' # Use Puma as the app server gem 'puma', '~> 3.0' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.2' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby # Use jquery as the JavaScript library gem 'jquery-rails' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 3.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platform: :mri end group :development do # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '~> 3.0.5' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] # bootstrap gem 'bootstrap-sass', '~> 3.4.1' # デバイス gem 'devise', '~>4.2' # Gravatar gem 'gravtastic' #フラッシュメッセージ gem 'toastr-rails', '~> 1.0' #日本語化 gem 'rails-i18n' #画像アップロード gem 'paperclip', '~> 5.1.0' #googleマップ gem 'geocoder', '~> 1.4' #アマゾンS3 gem 'aws-sdk', '~> 2.8' #日付ピッカー gem 'jquery-ui-rails', '~> 5.0' # 検索 gem 'ransack', '~> 1.7' # 電話番号認証 gem 'twilio-ruby', '~> 4.11.1'
コマンド
bundle
「config\initializers」フォルダに「twilio.rb」ファイルを新規作成してください。
config\initializers\twilio.rb(新規作成したファイル)
ご自分のアカウントSIDとAUTHTOKENを入れて下さい。
Twilio.configure do |config| config.account_sid = 'AC6c3786554525790e777ea3bca592a70e' config.auth_token = 'ae5debedfafff4ddd84634f6d505edd1' end
コマンド
rails g migration AddPinAndPhoneVerifiedToUser pin phone_verified:boolean
コマンド
rails db:migrate
記述追加 app\models\user.rb(22行目)
10行目「from」にはTwilioで無料取得したご自分のアメリカの電話番号を入力して下さい。
def generate_pin self.pin = SecureRandom.hex(2) self.phone_verified = false save end def send_pin @client = Twilio::REST::Client.new @client.messages.create( from: '+12056565281', to: self.phone_number, body: "テストサイトMinpakuです。あなたのPinコードは #{self.pin}" ) end def verify_pin(entered_pin) update(phone_verified: true) if self.pin == entered_pin end
app\models\user.rb
31行目「from」にはTwilioで無料取得したご自分のアメリカの電話番号を入力して下さい。
class User < ApplicationRecord # アバター画像表示用 include Gravtastic gravtastic # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable #長さ50文字以下 入力必須 validates :fullname, presence: true, length: {maximum: 50} has_many :rooms has_many :reservations has_many :guest_reviews, class_name: "GuestReview", foreign_key: "guest_id" has_many :host_reviews, class_name: "HostReview", foreign_key: "host_id" def generate_pin self.pin = SecureRandom.hex(2) self.phone_verified = false save end def send_pin @client = Twilio::REST::Client.new @client.messages.create( from: '+12056565281', to: self.phone_number, body: "テストサイトMinpakuです。あなたのPinコードは #{self.pin}" ) end def verify_pin(entered_pin) update(phone_verified: true) if self.pin == entered_pin end end
記述追加 app\controllers\users_controller.rb(14行目から)
def update_phone_number current_user.update_attributes(user_params) # 日本の電話国番号+81を先頭につける japan_number = user_params[:phone_number].sub(/\A./,'+81') current_user.update_attributes(phone_number: japan_number) current_user.generate_pin current_user.send_pin redirect_to edit_user_registration_path, notice: "保存しました。" rescue Exception => e redirect_to edit_user_registration_path, alert: "#{e.message}" end def verify_phone_number current_user.verify_pin(params[:user][:pin]) if current_user.phone_verified flash[:notice] = "電話番号が確認されました。" else flash[:alert] = "電話番号を確認できません。" end redirect_to edit_user_registration_path rescue Exception => e redirect_to edit_user_registration_path, alert: "#{e.message}" end private def user_params params.require(:user).permit(:phone_number, :pin) end
app\controllers\users_controller.rb
class UsersController < ApplicationController def show @user = User.find(params[:id]) @rooms = @user.rooms # ユーザーがホストの場合、ホストに対するすべてのゲストレビューを表示 @guest_reviews = Review.where(type: "GuestReview", host_id: @user.id) # ユーザーがゲストの場合、ユーザに対するすべてのホストレビューを表示 @host_reviews = Review.where(type: "HostReview", guest_id: @user.id) end def update_phone_number current_user.update_attributes(user_params) # 日本の電話国番号+81を先頭につける japan_number = user_params[:phone_number].sub(/\A./,'+81') current_user.update_attributes(phone_number: japan_number) current_user.generate_pin current_user.send_pin redirect_to edit_user_registration_path, notice: "保存しました。" rescue Exception => e redirect_to edit_user_registration_path, alert: "#{e.message}" end def verify_phone_number current_user.verify_pin(params[:user][:pin]) if current_user.phone_verified flash[:notice] = "電話番号が確認されました。" else flash[:alert] = "電話番号を確認できません。" end redirect_to edit_user_registration_path rescue Exception => e redirect_to edit_user_registration_path, alert: "#{e.message}" end private def user_params params.require(:user).permit(:phone_number, :pin) end end
記述更新 config\routes.rb(12行目)
resources :users, only: [:show] do member do post '/verify_phone_number' => 'users#verify_phone_number' patch '/update_phone_number' => 'users#update_phone_number' end end
config\routes.rb
Rails.application.routes.draw do #ルートをpages#homeに設定 root 'pages#home' get 'pages/home' get '/your_trips' => 'reservations#your_trips' get '/your_reservations' => 'reservations#your_reservations' get 'search' => 'pages#search' get 'dashboard' => 'dashboards#index' resources :users, only: [:show] do member do post '/verify_phone_number' => 'users#verify_phone_number' patch '/update_phone_number' => 'users#update_phone_number' end end resources :rooms, except: [:edit] do member do get 'listing' get 'pricing' get 'description' get 'photo_upload' get 'amenities' get 'location' get 'preload' get 'preview' end resources :photos, only: [:create, :destroy] resources :reservations, only: [:create] end resources :guest_reviews, only: [:create, :destroy] resources :host_reviews, only: [:create, :destroy] devise_for :users, path: '', path_names: {sign_in: 'login', sign_out: 'logout', edit: 'profile', sign_up: 'registration'}, controllers: {registrations: 'registrations'} # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
記述追加 app\views\devise\registrations\edit.html.erb
51行目から電話番号入力フィールドの記述を追加しています。
コードをコピーしてファイルを置き換えてください。
<div class="row"> <div class="col-md-3"> <ul class="sidebar-list"> <li class="sidebar-item"><%= link_to "ユーザ登録情報の編集", edit_user_registration_path, class: "sidebar-link active" %></li> </ul> <br/> <%= link_to "登録情報を確認する", user_path(current_user.id), class: "btn btn-default" %> </div> <div class="col-md-9 text-center"> <div class="panel panel-default"> <div class="panel-heading">登録情報 追加・修正</div> <div class="panel-body"> <div class="container"> <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= render 'shared/devisemes' %> <div class="form-group"> <%= f.text_field :fullname, autofocus: true, placeholder: "氏名", class: "form-control" %> </div> <div class="form-group"> <%= f.text_area :description, rows: 5, cols: 25, autofocus: true, placeholder: "説明", class: "form-control" %> </div> <div class="form-group"> <%= f.email_field :email, autofocus: true, placeholder: "メールアドレス", class: "form-control" %> </div> <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> <div>現在、次の確認を待っています: <%= resource.unconfirmed_email %></div> <% end %> <div class="form-group"> <%= f.password_field :password, autocomplete: "off", placeholder: "パスワード (変更しない場合は空白のまま)", class: "form-control" %> <div class="form-group"> <%= f.password_field :password_confirmation, autocomplete: "off", placeholder: "確認(変更しない場合は空白のまま)", class: "form-control" %> </div> <div class="actions"> <%= f.submit "保存する", class: "btn btn-normal btn-block" %> </div> <% end %> </div> </div> </div> <br/> <div class="panel panel-default"> <div class="panel-heading">あなたの電話番号</div> <div class="panel-body"> <div class="container"> <% if !current_user.phone_number.blank? %> <h4><%= current_user.phone_number %></h4> <% if current_user.phone_verified == false %> <button class="btn btn-default" data-toggle="modal" data-target="#verify-phone">PINコード入力</button> <% else %> <button class="btn btn-default" data-toggle="modal" data-target="#update-phone">電話番号を更新</button> <% end %> <% else %> <button class="btn btn-default" data-toggle="modal" data-target="#update-phone">電話番号を追加</button> <% end %> </div> </div> </div> </div> </div> <!-- 電話番号のMODAL --> <div id="update-phone" class="modal fade" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button class="close" data-dismiss="modal">×</button> <h4 class="modal-title">電話番号</h4> </div> <div class="modal-body"> <%= form_for current_user, url: update_phone_number_user_path(current_user) do |f| %> <div class="form-group"> <%= f.phone_field :phone_number, class: "form-control", placeholder: "電話番号を入力してください。" %> </div> <div class="text-center"> <%= f.submit "保存する", class: "btn btn-normal" %> </div> <% end %> </div> </div> </div> </div> <!-- PINコード入力のMODAL --> <div id="verify-phone" class="modal fade" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button class="close" data-dismiss="modal">×</button> <h4 class="modal-title">PINコード</h4> </div> <div class="modal-body"> <%= form_for current_user, url: verify_phone_number_user_path(current_user), method: :post do |f| %> <div class="form-group"> <%= f.text_field :pin, class: "form-control", placeholder: "SMS送信されたPINコードを入力", value: "" %> </div> <div class="text-center"> <%= f.submit "確認する", class: "btn btn-normal" %> </div> <% end %> </div> </div> </div> </div>
ブラウザ確認
http://localhost:3000/profile
「電話番号追加」をクリックします。
携帯電話番号を入力して下さい。
電話番号は保存されますが「phone_verified」はまだ「false」です。
ショートメールでPinコードが届きますので入力します。
「phone_verified」が「ture」になりました。
記述追加 app\views\dashboards\index.html.erb(16行目)
<% if current_user.phone_verified %> <li>電話番号<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %>
app\views\dashboards\index.html.erb
<div class="row"> <div class="col-md-3"> <div class="center"> <%= image_tag current_user.gravatar_url, class: "avatar-full" %> </div> <div class="panel panel-default"> <div class="panel-heading"><%= current_user.fullname %></div> <div class="panel-body"> <ul class="sidebar-list"> <% if current_user.confirmation_token %> <li>メールアドレス<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %> <% if current_user.phone_verified %> <li>電話番号<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %> </ul> </div> </div> </div> <div class="col-md-9"> <!-- お知らせ --> <div class="panel panel-default"> <div class="panel-heading">お知らせ</div> <div class="panel-body"> </div> </div> <!-- 登録している部屋 --> <div class="panel panel-default"> <div class="panel-heading">登録しているお部屋(<%= @rooms.length %>)</div> <div class="panel-body"> <%= render partial: "rooms/rooms_list", locals: {rooms: @rooms} %> </div> </div> </div> </div>
ブラウザ確認
http://localhost:3000/dashboard
電話番号が登録されている場合チェックマークがつくようになりました。
記述追加 app\views\users\show.html.erb(21行目)
<% if @user.phone_verified %> <li>電話番号<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %>
app\views\users\show.html.erb
<div class="row"> <div class="col-md-3"> <div class="center"> <%= image_tag @user.gravatar_url, class: "avatar-full" %> </div> <div class="panel panel-default"> <div class="panel-heading" style="text-align: center;"><%= @user.fullname %></div> <br/> <div class="center"> <%= @user.description %> </div> <hr/> <div class="panel-body"> <ul class="sidebar-list"> <% if @user.confirmation_token %> <li>Emailアドレス<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %> <% if @user.phone_verified %> <li>電話番号<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li> <% end %> </ul> </div> </div> </div> <div class="col-md-9"> <br/> <h4><%= @user.fullname %>さんが登録しているお部屋(<%= @rooms.length %>)</h4><br/> <div class="row"> <%= render partial: "rooms/rooms_list", locals: {rooms: @rooms} %> </div> <br/> <h4>ゲストからのレビュー (<%= @guest_reviews.count %>)</h4> <div class="row"> <%= render "reviews/guest_list" %> </div> <br/> <h4>ホストからのレビュー (<%= @host_reviews.count %>)</h4> <div class="row"> <%= render "reviews/host_list" %> </div> <br/> </div> </div>
ブラウザ確認
同じく電話番号の登録欄をつけました。
http://localhost:3000/users/3