↓↓クリックして頂けると励みになります。
【29 | Datepicker】 << 【ホーム】 >> 【31 | 予約確認】
実際に予約ができるよう、実装していきます。
「app\controllers\rooms_controller.rb」ファイルを編集します。
1.記述追加 app\controllers\rooms_controller.rb(75行目)
# 予約 開始日の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(113行目)
# 予約 プライベートメソッド 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, :photo_upload, :delete_photo, :amenities, :location, :update] def index @rooms = Room.all 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 @i = 0 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, :latitude, :longitude, :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'」の記述追加(22行目)と「get 'preview'」の記述追加(23行目)
Rails.application.routes.draw do # ルートを app\views\pages\home.html.erb に設定 root 'pages#home' # get get 'pages/home' get '/dashboard', to: 'users#dashboard' get '/users/:id', to: 'users#show', as: 'user' # post 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 # device devise_for :users, path: '', path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'}, controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'} # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Can be used by load balancers and uptime monitors to verify that the app is live. get "up" => "rails/health#show", as: :rails_health_check # Defines the root path route ("/") # root "posts#index" end
スクリプトを大幅に書き足しています。
記述更新 app\views\reservations\_form.html.erb
<%= form_for([@room, @room.reservations.new]) do |f| %> <div class="card"> <div class="card-body"> <span class="badge bg-danger mb-2">1泊 <%= number_to_currency(@room.price) %></span> <h5 class="card-title text-danger h4 font1 mb-4"><strong><span>予約はこちら</span></strong></h5> <% if (!user_signed_in?) %> <%= link_to "ログインすると予約ができます", new_user_session_path, class: "btn btn-success text-light" %> <% else %> <div class="row mb-4"> <div class="col-6"> <span class="badge bg-success">チェックイン </span> <%= f.text_field :start_date, readonly: true, placeholder: "チェックイン", class: "form-control" %> </div> <div class="col-6"> <span class="badge bg-primary">チェックアウト</span> <%= f.text_field :end_date, readonly: true, placeholder: "チェックアウト", class: "form-control" %> </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><span class="badge bg-secondary">1泊料金</span></td> <td class="text-right", style="white-space: nowrap"><%= number_to_currency(@room.price) %></td> </tr> <tr> <td><span class="badge bg-secondary">宿泊数</span></td> <td class="text-right"><span id="reservation_nights"></span>泊</td> </tr> <tr> <td class="total"><span class="badge bg-info">合計料金</span></td> <td class="text-right", style="white-space: nowrap"><span id="reservation_total"></span>円</td> </tr> </tbody> </table> </div> <div class="mt-4"> <%= f.submit "予約する", id: "btn_book", class: "btn btn-danger w-100", disabled: true %> </div> <% end %> </div> </div> <% end %> <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 if(nights ==0 ){ $('#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); } } }); } }); } }); }); //確認ダイアログ用 function check_form() { var start_date = $('#reservation_start_date').datepicker('getDate'); var end_date = $('#reservation_end_date').datepicker('getDate'); var check_in_year = start_date.getFullYear() var check_in_month = start_date.getMonth()+1 var check_in_day = start_date.getDate() var check_out_year = end_date.getFullYear() var check_out_month = end_date.getMonth()+1 var check_out_day = end_date.getDate() var nights = (end_date - start_date)/1000/60/60/24; var total = nights * <%= @room.price %> var listing_name = '<%= @room.listing_name %>' var submitMessage = window.confirm( listing_name + 'の予約内容を確認してください。\r\n\r\n'+ 'チェックイン: ' + check_in_year + '年' + check_in_month +'月' + check_in_day + '日 14:00〜\r\n' + 'チェックアウト: '+ check_out_year + '年' + check_out_month +'月' + check_out_day + '日 〜11:00\r\n' +'宿泊日数: ' + nights + '泊\r\n' + '合計金額: ' + total + '円(税+サービス料含む)\r\n\r\n' + 'この内容で予約してもよろしいですか?' ); if (!submitMessage) { return false; }; }; </script>
実際に予約をして動作を確認してください。
ログインしないと予約カレンダーが出ないようになっています。
実際に予約できるか確認してください。
ブラウザ確認
http://localhost:3000/rooms/1
【29 | Datepicker】 << 【ホーム】 >> 【31 | 予約確認】
↓↓クリックして頂けると励みになります。