学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

【民泊5.1】【MacOSX】SMSと電子メールの選択

予約完了時のメール送信を宿泊者(ゲスト)が選択できるようにします。


コマンド
rails g model Setting enable_sms:boolean enable_email:boolean user:references


記述更新 db\migrate\20200701094041_create_settings.rb
コードをコピーしてファイルを置き換えて下さい。

class CreateSettings < ActiveRecord::Migration[5.0]
  def change
    create_table :settings do |t|
      t.boolean :enable_sms, default: true
      t.boolean :enable_email, default: true
      t.references :user, foreign_key: true

      t.timestamps
    end

    User.find_each do |user|
       Setting.create(user: user, enable_email: true, enable_sms: true)
    end

  end
end



コマンド マイグレーション
rails db:migrate


記述追加 app\models\user.rb(22行目)

  has_one :setting
  after_create :add_setting

  def add_setting
    Setting.create(user: self, enable_sms: true, enable_email: true)
  end



app\models\user.rb

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, :omniauthable

  #長さ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"

  has_one :setting
  after_create :add_setting

  def add_setting
    Setting.create(user: self, enable_sms: true, enable_email: true)
  end

  def self.from_omniauth(auth)
    user = User.where(email: auth.info.email).first

    if user
      return user
    else
      where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
        user.email = auth.info.email
        user.password = Devise.friendly_token[0,20]
        user.fullname = auth.info.name
        user.image = auth.info.image
        user.uid = auth.uid
        user.provider = auth.provider

        user.skip_confirmation!
      end
    end
  end

  def is_active_host
    !self.merchant_id.blank?
  end

  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」フォルダに「settings_controller.rb」ファイルを新規作成してください。


app\controllers\settings_controller.rb(新規作成したファイル)

class SettingsController < ApplicationController
    def edit
      @setting = User.find(current_user.id).setting
    end
  
    def update
      @setting = User.find(current_user.id).setting
      if @setting.update(setting_params)
        flash[:notice] = "保存しました"
      else
        flash[:alert] = "保存できません"
      end
      render 'edit'
    end
  
    private

    def setting_params
        params.require(:setting).permit(:enable_sms, :enable_email)
    end

end



記述追加 config\routes.rb
14行目に「get '/notification_settings' => 'settings#edit'」の記述追加。
17行目に「post '/notification_settings' => 'settings#update'」の記述追加。

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'
  get '/host_calendar' => "calendars#host"
  get '/payment_method' => "users#payment"
  get '/payout_method' => "users#payout"
  get '/notification_settings' => 'settings#edit'

  post '/add_card' => "users#add_card"
  post '/notification_settings' => 'settings#update'

  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]
    resources :calendars
  end

  resources :guest_reviews, only: [:create, :destroy]
  resources :host_reviews, only: [:create, :destroy]

  resources :revenues, only: [:index]

  resources :reservations, only: [:approve, :decline] do
    member do
      post '/approve' => "reservations#approve"
      post '/decline' => "reservations#decline"
    end
  end

  devise_for :users,
  path: '',
  path_names: {sign_in: 'login', sign_out: 'logout', edit: 'profile', sign_up: 'registration'},
  controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end



記述更新 app\controllers\reservations_controller.rb(91, 92行目)

send_sms(room, reservation) if reservation.user.setting.enable_sms
ReservationMailer.send_email_to_guest(reservation.user, room, reservation).deliver_later if reservation.user.setting.enable_email



app\controllers\reservations_controller.rb

class ReservationsController < ApplicationController

  before_action :authenticate_user!
  before_action :set_reservation, only: [:approve, :decline]

  def create
    room = Room.find(params[:room_id])

    if current_user == room.user
      flash[:alert] = "オーナーが予約することはできません。"
    elsif current_user.stripe_id.blank?
      flash[:alert] = "予約する前にクレジットカードを登録する必要があります。"
      return redirect_to payment_method_path
    else

        start_date = Date.parse(reservation_params[:start_date])
        end_date = Date.parse(reservation_params[:end_date])
        days = (end_date - start_date).to_i
      if days == 0
        flash[:alert] = "宿泊日数が1泊以上でなければ予約することはできません。"
      else
        @reservation = current_user.reservations.build(reservation_params)
        @reservation.room = room
        @reservation.price = room.price
        @reservation.total = room.price * days
        #@reservation.save

        if @reservation.Waiting!
          if room.Request?
            flash[:notice] = "予約承認申請を送信しました。予約が承認されるまでしばらくお待ち下さい。"
          else
            charge(room, @reservation)
          end
        else
          flash[:alert] = "ご予約できません!"
        end
      end
    end
    redirect_to room
  end

  # 宿泊者用予約確認
  def your_trips
    @trips = current_user.reservations.order(start_date: :asc)
  end

  #ホスト用予約確認
  def your_reservations
    @rooms = current_user.rooms
  end

  def approve
    charge(@reservation.room, @reservation)
    redirect_to your_reservations_path
  end

  def decline
    @reservation.Declined!
    redirect_to your_reservations_path
  end
  
  private

  def send_sms(room, reservation)
    @client = Twilio::REST::Client.new
    @client.messages.create(
      from: '+12056565281',
      to: room.user.phone_number,
      body: "#{reservation.user.fullname}様、#{room.listing_name}を予約しました。"
    )
  end

  def charge(room, reservation)
    host_amount = (reservation.total * 0.8).to_i # 売上の80%がホストに入る
    if !reservation.user.stripe_id.blank?
      customer = Stripe::Customer.retrieve(reservation.user.stripe_id)
      charge = Stripe::Charge.create(
        :customer => customer.id,
        :amount => reservation.total,
        :description => room.listing_name,
        :currency => "jpy",
        transfer_data: {
          amount: host_amount, 
          destination: room.user.merchant_id, # ホストのストライプID
        },
      )

      if charge
        reservation.Approved!

        send_sms(room, reservation) if reservation.user.setting.enable_sms
        ReservationMailer.send_email_to_guest(reservation.user, room, reservation).deliver_later if reservation.user.setting.enable_email
        flash[:notice] = "お支払い手続きが完了し、ご予約されました。お越しをお待ちしております!"
      else
        reservation.Declined!
        flash[:notice] = "お支払い手続きができません。予約ができませんでした。"
      end
    end
  rescue Stripe::CardError => e
    reservation.declined!
    flash[:alert] = e.message
  end

  def set_reservation
    @reservation = Reservation.find(params[:id])
  end

  def reservation_params
    params.require(:reservation).permit(:start_date, :end_date)
  end
  
end
  



「app\views」フォルダに「settings」フォルダを新規作成して下さい。
作成した「settings」フォルダに「edit.html.erb」ファイルを新規作成します。



app\views\settings\edit.html.erb(新規作成したファイル)

<div class="row">
  <div class="col-md-3">
    <ul class="sidebar-list">
      <li class="sidebar-item"><%= link_to "通知設定", notification_settings_path, class: "sidebar-link active" %></li>
    </ul>
  </div>
  <div class="col-md-9">
    <div class="panel panel-default">
      <div class="panel-heading">通知設定</div>
      <div class="panel-body">
        <div class="container">
            <p>ここでは予約完了時の確認メール送信設定が行えます。</p>
            <br/>
            <%= form_for :setting do |f| %>
              <div class="row form-group">
                <div class="col-md-6 text-center">
                  <%= f.check_box :enable_email %> 電子メール
                </div>
                <div class="col-md-6 text-center">
                  <%= f.check_box :enable_sms %> ショートメール
                </div>
              </div>
              <div class="text-center">
                <%= f.submit "設定を保存", class: "btn btn-normal" %>
              </div>
            <% end %>
        </div>
      </div>
    </div>
  </div>
</div>



ブラウザ確認
http://localhost:3000/notification_settings


宿泊者(ゲスト)が予約時の確認メールを選択できるようになりました。

予約時確認メール選択
予約時確認メール選択


ナビゲーションバーのリンクを追加します。


記述追加 app\views\shared\_navbar.html.erb
42行目と63行目にリンクの記述を追加しています。

<!-- ナビゲーションバー -->
<nav class="navbar navbar-default navbar-static-top"  style ="margin: 0;">

  <div class="container">

    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
        <span class="sr-only">ナビゲーション トグル</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <%= link_to "テストサイトMinpaku", root_path, class: "navbar-brand" %>
    </div>

    <div id="navbar" class="navbar-collapse collapse">
      <ul class="nav navbar-nav navbar-right">
        <% if (!user_signed_in?) %>
            <li><%= link_to "ログイン", new_user_session_path %></li>
            <li><%= link_to "新規ユーザ登録", new_user_registration_path %></li>
        <% else %>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                <!-- アバター画像 -->
                <%= image_tag current_user.gravatar_url, class: "img-circle avatar-small" %>&nbsp;
                <!-- 氏名表示に変更 -->
                <%= current_user.fullname %>
                <span class="caret"></span>
              </a>
              <ul class="dropdown-menu">
                <li><%= link_to "ダッシュボード", dashboard_path %></li>
                <li><%= link_to "登録したお部屋の管理", rooms_path %></li>
                <li><%= link_to "お部屋の新規登録", new_room_path %></li>
                <li><%= link_to "受注予約の管理(ホスト用)", your_reservations_path %></li>
                <li><%= link_to "予約履歴(ゲスト用)", your_trips_path %></li>
                <li><%= link_to "ホスト用カレンダー", host_calendar_path %></li>
                <li><%= link_to "収益", revenues_path %></li>
                <li><%= link_to "クレジットカード登録", payment_method_path, data: { turbolinks: false} %></li>
                <li><%= link_to "振り込み口座登録", payout_method_path %></li>                
                <li role="separator" class="divider"></li>
                <li><%= link_to "ユーザ登録情報修正", edit_user_registration_path %></li>
                <li><%= link_to "予約メール通知設定", notification_settings_path %></li>
                <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
              </ul>
            </li>
        <% end %>
      </ul>
    </div>
    
  </div>

</nav>

<% if (user_signed_in?) && !current_page?(root_path) && !current_page?("/rooms/#{params[:id]}") %>
    <nav class="navbar navbar-default" style="background-color: #89dfd7;">
      <div class="container">
        <ul class="nav navbar-nav">
          <li <% if current_page?(dashboard_path) %> class="active" <% end %> > <%= link_to "ダッシュボード", dashboard_path %></li>
          <li <% if current_page?(host_calendar_path) %> class="active" <% end %> ><%= link_to "ホスト用カレンダー", host_calendar_path %></li>
          <li <% if current_page?(revenues_path) %> class="active" <% end %> ><%= link_to "収益", revenues_path %></li>
          <li <% if current_page?(payment_method_path) %> class="active" <% end %> ><%= link_to "クレジットカード登録", payment_method_path, data: { turbolinks: false} %></li>
          <li <% if current_page?(payout_method_path) %> class="active" <% end %> ><%= link_to "振り込み口座登録", payout_method_path %></li>
          <li <% if current_page?(notification_settings_path) %> class="active" <% end %> ><%= link_to "予約メール通知設定", notification_settings_path %></li>
        </ul>
      </div>
    </nav>
<% end %>