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

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

【民泊6.0】【Windows】予約フォーム

「app\controllers\rooms_controller.rb」ファイルを編集します。


1.記述追加 app\controllers\rooms_controller.rb(71行目)

  # 予約 開始日のAJAX
  def preload
    today = Date.today
    reservations = @room.reservations.where("start_date >= ? OR end_date >= ?", today, today)

    render json: reservations
  end

  # 予約 終了日のAJAX
  def preview
    start_date = Date.parse(params[:start_date])
    end_date = Date.parse(params[:end_date])

    output = {
      conflict: is_conflict(start_date, end_date, @room)
    }

    render json: output
  end



2.記述追加 app\controllers\rooms_controller.rb(105行目)

    # 予約 プライベートメソッド
    def is_conflict(start_date, end_date, room)
      check = room.reservations.where("? < start_date AND end_date < ?", start_date, end_date)
      check.size > 0? true : false
    end



app\controllers\rooms_controller.rb

class RoomsController < ApplicationController

  protect_from_forgery except: [:upload_photo]
  before_action :set_room, except: [:index, :new, :create]
  before_action :authenticate_user!, except: [:show]
  before_action :is_authorised, only: [:listing, :pricing, :description, :photo_upload, :amenities, :location, :update]

  def index
     @rooms = current_user.rooms
  end

  def new
    @room = current_user.rooms.build
  end

  def create
    @room = current_user.rooms.build(room_params)
    if @room.save
      redirect_to listing_room_path(@room), notice: "保存しました。"
    else
      flash[:alert] = "問題が発生しました。"
      render :new
    end
  end

  def show
    @photos = @room.photos
  end

  def listing
  end

  def pricing
  end

  def description
  end

  def photo_upload
  end

  def amenities
  end

  def location
  end

  def update
    new_params = room_params
    new_params = room_params.merge(active: true) if is_ready_room

    if @room.update(new_params)
      flash[:notice] = "保存しました。"
    else
      flash[:alert] = "問題が発生しました。"
    end
    redirect_back(fallback_location: request.referer)
  end

  def upload_photo
    @room.photos.attach(params[:file])
    render json: { success: true }
  end

  def delete_photo
    @image = ActiveStorage::Attachment.find(params[:photo_id])
    @image.purge
    redirect_to photo_upload_room_path(@room)
  end

  # 予約 開始日のAJAX
  def preload
    today = Date.today
    reservations = @room.reservations.where("start_date >= ? OR end_date >= ?", today, today)
    render json: reservations
  end
  # 予約 終了日のAJAX
  def preview
    start_date = Date.parse(params[:start_date])
    end_date = Date.parse(params[:end_date])
    output = {
      conflict: is_conflict(start_date, end_date, @room)
    }
    render json: output
  end

  private

    def set_room
      @room = Room.find(params[:id])
    end
    
    def room_params
      params.require(:room).permit(:home_type, :room_type, :accommodate, :bed_room, :bath_room, :listing_name, :summary, :address, :is_tv, :is_kitchen, :is_air, :is_heating, :is_internet, :price, :active, :description)
    end

    def is_authorised
      redirect_to root_path, alert: "権限がありません。" unless current_user.id == @room.user_id
    end

    def is_ready_room
      !@room.active && !@room.price.blank? && !@room.listing_name.blank? && !@room.photos.blank? && !@room.address.blank?
    end

    # 予約 プライベートメソッド
    def is_conflict(start_date, end_date, room)
      check = room.reservations.where("? < start_date AND end_date < ?", start_date, end_date)
      check.size > 0? true : false
    end

  end



記述追加 config\routes.rb
「get 'preload'」の記述追加(25行目)と「get 'preview'」の記述追加(26行目)

Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  devise_for :users, 
              path: '', 
              path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
              controllers: {registrations: 'registrations'}

  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show', as: 'user'
  
  post '/users/edit', to: 'users#update'

  resources :rooms, except: [:edit] do
    member do
      get 'listing'
      get 'pricing'
      get 'description'
      get 'photo_upload'
      get 'amenities'
      get 'location'
      get 'preload'
      get 'preview'
      delete :delete_photo
      post :upload_photo
    end
    resources :reservations, only: [:create]
  end

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end



記述更新 app\views\reservations\_form.html.erb
コードをコピーして内容を置き換えてください。

<div class="card">
  <header class="card-header">
    <p class="card-header-title">
    <span><i class="fas fa-chess-king" style="color: #ffb400"></i></span>&nbsp;&nbsp;&nbsp;
    <span class="pull-right">1泊 <%= number_to_currency(@room.price) %></span>
    </p>
  </header>
  <div class="card-content">
    <div class="content">

      <%= form_for([@room, @room.reservations.new]) do |f| %>

        <div class="field is-horizontal">
            <div class="field-body">
                <div class="field">
                <p class="control is-expanded has-icons-left">
                    <%= f.text_field :start_date, readonly: true, placeholder: "イン", class: "input is-primary is-rounded" %>
                    <span class="icon is-small is-left">
                    <i class="far fa-calendar-alt"></i>
                    </span>
                </p>
                </div>
                <div class="field">
                <p class="control is-expanded has-icons-left has-icons-right">
                    <%= f.text_field :end_date, readonly: true, placeholder: "アウト", class: "input is-primary is-rounded" %>
                    <span class="icon is-small is-left">
                    <i class="far fa-calendar-alt"></i>
                    </span>

                </p>
                </div>
            </div>
        </div>

        <h4 class="message-alert text-center"><span id="message"></span></h4>
        <div id="preview" style="display: none">
          <table class="reservation-table">
            <tbody>
                <tr>
                  <td>宿泊費用</td>
                  <td class="text-right", style="white-space: nowrap"><%= number_to_currency(@room.price) %></td>
                </tr>
                <tr>
                  <td>宿泊日数</td>
                  <td class="text-right"><span id="reservation_nights"></span></td>
                </tr>
                <tr>
                  <td class="total">合計金額</td>
                  <td class="text-right", style="white-space: nowrap"><span id="reservation_total"></span></td>
                </tr>
              </tbody>
          </table>
        </div>

        <%= f.submit "予約する", class: "button is-danger is-fullwidth m-t-10 m-b-10"  %>
      <% end %>

    </div>
  </div>
</div>

<script>
  function checkDate(date) {
    dmy = date.getDate() + "-" + (date.getMonth() + 1) + "-" + date.getFullYear();
    return [$.inArray(dmy, unavailableDates) == -1];
  }
  $(function() {
    unavailableDates = [];
    $.ajax({
      url: '<%= preload_room_path(@room) %>',
      dateTyp: 'json',
      success: function(data) {
        $.each(data, function(arrID, arrValue) {
            for(var d = new Date(arrValue.start_date); d <= new Date(arrValue.end_date); d.setDate(d.getDate() + 1)) {
              unavailableDates.push($.datepicker.formatDate('d-m-yy', d));
            }
        });
        $('#reservation_start_date').datepicker({
          dateFormat: 'dd-mm-yy',
          //今日から3ヶ月先まで予約可能
          minDate: 0,
          maxDate: '3m',
          beforeShowDay: checkDate,
          onSelect: function(selected) {
            $('#reservation_end_date').datepicker("option", "minDate", selected);
            $('#reservation_end_date').attr("disabled", false);
            var start_date = $('#reservation_start_date').datepicker('getDate');
            var end_date = $('#reservation_end_date').datepicker('getDate');
            //2日選択すると1泊になる
            var nights = (end_date - start_date)/1000/60/60/24;
            var input = {
              'start_date': start_date,
              'end_date': end_date
            }
            $.ajax({
              url: '<%= preview_room_path(@room) %>',
              data: input,
              success: function(data) {
                if(data.conflict) {
                  $('#message').text("この日付はご利用できません。");
                  $('#preview').hide();
                  $('#btn_book').attr('disabled', true);
                } else {
                  $('#message').text("");
                  $('#preview').show();
                  $('#btn_book').attr('disabled', false);
                  var total = nights * <%= @room.price %>
                  $('#reservation_nights').text(nights);
                  $('#reservation_total').text(total);
                }
              }
            });
          }
        });
        $('#reservation_end_date').datepicker({
          dateFormat: 'dd-mm-yy',
          //今日から3ヶ月先まで予約可能
          minDate: 0,
          maxDate: '3m',
          beforeShowDay: checkDate,
          onSelect: function(selected) {
            $('#reservation_start_date').datepicker("option", "maxDate", selected);
            var start_date = $('#reservation_start_date').datepicker('getDate');
            var end_date = $('#reservation_end_date').datepicker('getDate');
            var nights = (end_date - start_date)/1000/60/60/24;
            var input = {
              'start_date': start_date,
              'end_date': end_date
            }
            $.ajax({
              url: '<%= preview_room_path(@room) %>',
              data: input,
              success: function(data) {
                if(data.conflict) {
                  $('#message').text("この日付ではご予約できません。");
                  $('#preview').hide();
                  $('#btn_book').attr('disabled', true);
                } else {
                  $('#message').text("");
                  $('#preview').show();
                  $('#btn_book').attr('disabled', false);
                  var total = nights * <%= @room.price %>
                  $('#reservation_nights').text(nights);
                  $('#reservation_total').text(total);
                }
              }
            });
          }
        });
      }
    });
  });
</script>



「app\views\rooms\show.html.erb」ファイルの記述を変更します。


記述変更 app\views\rooms\show.html.erb
265行目から267行目の記述を変更しています。

<section class="section">
    <div class="container">
        <div class="columns">

            <!-- 写真 -->
            <div class="card">
                <div class="card-content">
                    <div class="content">
                        <%= image_tag room_cover(@room) %>
                    </div>
                </div>
            </div>
            <br/>

        </div>
    </div>
</section>

<section class="section">
    <div class="container">
        <div class="columns">

            <!-- 左側 -->
            <div class="column is-two-thirds">
                <div class="columns is-multiline">

                    <div class="column">
                        <div class="card">
                            <div class="card-content">

                                
                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">

                                                <!-- お部屋の名前 -->
                                                <div class="row">
                                                    <div class="col-md-8">
                                                        <h1><%= @room.listing_name %></h1>
                                                        <h2><%= @room.address %></h2>
                                                    </div>
                                                 
                                                </div>
                                            </div>
                                        </div>
                                    </article>
                                </div>

                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">
                                                <span class="title is-5"><%= @room.user.full_name %></span>
                                                <figure class="image is-96x96">
                                                    <%= image_tag avatar_url(@room.user), class: "is-rounded" %>
                                                </figure>
                                            </div>

                                        </div>
                                    </article>
                                </div>

                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">

                                                <!-- 部屋のインフォメーション -->
                                                <div style="white-space: nowrap">

                                                    <span class="col-md-3">
                                                        <i class="fas fa-home fa-3x" style="color: #1dbf73"></i>
                                                        <span class="col-md-3"><%= @room.home_type %></span>
                                                    </span>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <span class="col-md-3">
                                                        <i class="fas fa-user fa-3x" style="color: #1dbf73"></i>
                                                        <span class="col-md-3"><%= pluralize(@room.accommodate, "人") %></span>
                                                    </span>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <span class="col-md-3">
                                                        <i class="fas fa-bed fa-3x" style="color: #1dbf73"></i>
                                                        <span class="col-md-3"><%= pluralize(@room.bed_room, "台") %></span>
                                                    </span>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <span class="col-md-3">
                                                        <i class="fas fa-bath fa-3x" style="color: #1dbf73"></i>
                                                        <span class="col-md-3"><%= pluralize(@room.bath_room, "部屋") %></span>
                                                    </span>
                                                </div>

                                            </div>

                                        </div>
                                    </article>
                                </div>

                                <!-- お部屋の詳細 -->
                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">
                                                <h3>お部屋の詳細</h3>
                                                <p><%= @room.description %></p>

                                            </div>

                                        </div>
                                    </article>
                                </div>

                                <!-- アメニティー -->
                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">

                                                <div class="row">
                                                <div class="col-md-3">
                                                    <h4>アメニティ</h4>
                                                </div>
                                                <div class="col-md-9">
                                                    <div class="row">
                                                    <div class="col-md-6">
                                                        <ul class="amenities">
                                                        <li class="<%= 'text-line-through' if !@room.is_tv %>">テレビ</li>
                                                        <li class="<%= 'text-line-through' if !@room.is_kitchen %>">キッチン</li>
                                                        <li class="<%= 'text-line-through' if !@room.is_internet %>">インターネット</li>
                                                        </ul>
                                                    </div>
                                                    <div class="col-md-6">
                                                        <ul class="amenities">
                                                        <li class="<%= 'text-line-through' if !@room.is_heating %>">暖房</li>
                                                        <li class="<%= 'text-line-through' if !@room.is_air %>">エアコン</li>
                                                        </ul>
                                                    </div>
                                                    </div>
                                                </div>
                                                </div>


                                            </div>

                                        </div>
                                    </article>
                                </div>


                            </div>
                        </div>                        
                    </div>

                    <!-- カルーセル表示 -->
                    <div class="column is-full">   

                        <div class="card">
                            <div class="card-content">
                                <div class="hero-carousel" id="carousel-photo">
                                    <% @room.photos.each do |photo| %>
                                        <div class="carousel-item has-background image is-16by9">
                                            <%= image_tag url_for(photo), class: "is-background", width: "100%" %>
                                        </div>
                                    <% end %>
                                </div>
                            </div>
                        </div>

                    </div>

             
                    <div class="column">
                        <div class="card">
                            <div class="card-content">

                                <!-- googleマップ -->
                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">

                                                <!-- GOOGLE マップ -->
                                                <div class="row">
                                                <div id="map" style="width: 100%; height: 400px"></div>
                                                <script src="https://maps.googleapis.com/maps/api/js"></script>
                                                <script>
                                                    function initialize() {
                                                        var location = {lat: <%= @room.latitude %>, lng: <%= @room.longitude %>};
                                                        var map = new google.maps.Map(document.getElementById('map'), {
                                                        center: location,
                                                        zoom: 14
                                                        });
                                                        var marker = new google.maps.Marker({
                                                        position: location,
                                                        map: map
                                                        });
                                                        var infoWindow = new google.maps.InfoWindow({
                                                        content: '<div id="content" class="image is-128x128"><%= image_tag room_cover(@room) %></div>'
                                                        });
                                                        infoWindow.open(map, marker);
                                                    }
                                                    google.maps.event.addDomListener(window, 'load', initialize);
                                                </script>
                                                <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBojDcZmScBkIOISjoYREjgid99iZUL2Tk&callback=initMap" type="text/javascript"></script>
                                                </div>

                                            </div>

                                        </div>
                                    </article>
                                </div>

                                <!-- 近くのお部屋 -->
                                <div class="box">
                                    <article class="media">

                                        <div class="media-content">
                                            <div class="content">

                                                <!-- 近くのお部屋を検索 -->
                                                <div class="row">
                                                    <h3>お近くのお部屋</h3>
                                                    <br/>
                                                    <% for room in @room.nearbys(10) %>
                                                        <div class="col-md-4">

                                                            <div class="image is-128x128">
                                                                <%= image_tag room_cover(@room) %>                    
                                                            </div>
                                                            <span>
                                                            <%= link_to room.listing_name, room %><br/>
                                                            (距離:<%= room.distance.round(2) %> Km)
                                                            </span>
                                                        </div>
                                                    <% end %>
                                                </div>
                                                
                                            </div>
                                        </div>
                                    </article>
                                </div>

 
                            </div>
                        </div>                        
                    </div>

                </div>
            </div>


            <!-- 右側 -->
            <div class="column">
                <div class="columns is-multiline">

                    <!-- 予約 -->
                    <div class="column is-full">

                        <div class="media">
                            <!-- 予約フォーム -->
                            <%= render 'reservations/form' %>
                        </div>

                    </div>


                </div>
            </div>
            
        </div>
    </div>
</section>


<script>
    BulmaCarousel.attach('#carousel-photo', {
        slidesToScroll: 1,
        slidesToShow: 1
    });

    $(document).ready(function() {
        $('#tabs li').on('click', function() {
            var type = $(this).data('tab');

            $('#tabs li').removeClass('is-active');
            $(this).addClass('is-active');

            $('.tab-content').hide();
            $('#tab-' + type).show();
        }) 
    })

</script>



ブラウザ確認
ログインしないと予約カレンダーが出ないようになっています。
実際に予約できるか確認してください。

http://localhost:3000/rooms/1

予約確認
予約確認