戻る

Rails5.0


民泊サイトの構築 Rails5.0

  (0)
2,000円

タスク5-5   カレンダーの改良

このタスクについて


タスクの内容を一部抜粋します。
プロジェクトを購入していただくとこのタスクの内容の全てを読みやすい表示で見ることができます。
プログラムコードが色分けされて見やすくなります。
プログラムコードに行番号が付きます。
本文が色分けされて見やすくなります。
そしてこのアプリケーションのフルコードをダウンロードすることが可能になります。




記述追加 app\views\calendars\host.html.erb(60行目)

カンマを忘れないようにして下さい。
 
, 
    dayRender: function(date, cell) { 
      <% if !@rooms.blank? %> 
          cell.append('<span class="day-price">' + '<%= @room.price %>円' + '</span>') 
      <% end %> 
    } 



app\views\calendars\host.html.erb
コードをコピーしてファイルを置き換えてください。
 
<% if !@rooms.blank? %> 
  <div class="row"> 
    <%= search_form_for @search, class: 'form-group', remote: true, url: host_calendar_path do |f| %> 
      <div class="col-md-6 select"> 
        <div class="form-group"> 
          <label>登録しているお部屋</label> 
          <%= f.select :room_id, options_for_select(@rooms.collect {|u| [u.listing_name, u.id]}, params[:room_id]), {}, { 
            onchange: "$(this.form).submit()", 
            class: "form-control" 
          } %> 
        </div> 
      </div> 
      <%= f.hidden_field :start_date, id: "start-date", value: params[:start_date], onchange: "$(this.form).submit()" %> 
    <% end %> 
  </div> 
<% end %> 
<div id="calendar"></div> 
<script> 
  window.reservations = <%= raw @events.to_json %> 
  console.log(reservations); 
  function showReservations(data) { 
    return data.map(function (e) { 
      if (e['start_date'] !== e['end_date']) { 
         e['end_date'] = moment.utc(e['end_date']).add(1, 'days') 
       } 
      return { 
        name: e.fullname, 
        start: e['start_date'], 
        end: e['end_date'], 
        avatar: e.image, 
        status: e.status 
      } 
    }) 
  } 
  $('#calendar').fullCalendar({ 
    header: { 
      left: 'title', 
      center: '', 
      right: 'prev,next' 
    }, 
    defaultDate: $('#start-date').val(), 
    events: showReservations(reservations), 
    eventRender: function(event, element, view) { 
      return $(` 
        <a class="fc-day-grid-event fc-h-event fc-event fc-start fc-end"> 
          <div class="fc-content ${event.status}"> 
            <span class="fc-title"><img class="img-circle avatar-small" src="${event.avatar}"> ${event.name}</span> 
          </div> 
        </a> 
      `); 
    }, 
    dayRender: function(date, cell) { 
      <% if !@rooms.blank? %> 
          cell.append('<span class="day-price">' + '<%= @room.price %>円' + '</span>') 
      <% end %> 
    } 
  }); 
  $('.fc-prev-button').click(function() { 
  var current = new Date($('#start-date').val()); 
  var prev = new Date(current.getFullYear(), current.getMonth() - 1, 1) 
  $('#start-date').val(moment(prev).format('YYYY-MM-DD')) 
  $('#start-date').trigger('change') 
}); 
$('.fc-next-button').click(function() { 
  var current = new Date($('#start-date').val()); 
  var next = new Date(current.getFullYear(), current.getMonth() + 1, 1) 
  $('#start-date').val(moment(next).format('YYYY-MM-DD')) 
  $('#start-date').trigger('change') 
}); 
</script> 



コマンド
rails g model Calendar day:date price:bigint status:bigint room:references


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


記述追加 app\models\room.rb
10行目に「has_many :calendars」の記述追加
 
class Room < ApplicationRecord 

  #    instant: {承認制: 0, すぐに予約: 1} 
  enum instant: {Request: 0, Instant: 1} 

  belongs_to :user 

  has_many :photos 
  has_many :reservations 
  has_many :guest_reviews 
  has_many :calendars 

  geocoded_by :address 

  after_validation :geocode, if: :address_changed? 

  validates :home_type, presence: true 
  validates :room_type, presence: true 
  validates :accommodate, presence: true 
  validates :bed_room, presence: true 
  validates :bath_room, presence: true 

  def cover_photo(size) 
    if self.photos.length > 0 
      self.photos[0].image.url(size) 
    else 
      "blank.jpg" 
    end 
  end 

  def average_rating 
    guest_reviews.count == 0 ? 0 : guest_reviews.average(:star).round(2).to_i 
  end  

end 



app\models\calendar.rb
 class Calendar < ApplicationRecord 
  #     status: [:利用可能, :利用不可] 
  enum status: [:Available, :Not_Available] 
  
  validates :day, presence: true 
  belongs_to :room 
end 



記述追加 config\routes.rb
33行目に「resources :calendars」の記述追加
 
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" 

  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 :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: {registrations: 'registrations'} 

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

end 



「app\views\calendars」フォルダに「_form.html.erb」ファイルを新規作成して下さい。


app\views\calendars\_form.html.erb(新規作成したファイル)
 
<div class="modal fade" id="new_calendar"> 
  <div class="modal-dialog"> 
    <div class="modal-content"> 
      <div class="modal-header"> 
        <button class="close" data-dismiss="modal">&times;</button> 
      </div> 
      <div class="modal-body"> 
        <%= form_for [@room, Calendar.new] do |f| %> 
            <div class="row"> 
              <div class="col-md-6"> 
                <div class="form-group"> 
                  <%= f.text_field :start_date, readonly: true, value: Date.today, class: "form-control datepicker" %> 
                </div> 
              </div> 
              <div class="col-md-6"> 
                <div class="form-group"> 
                  <%= f.text_field :end_date, readonly: true, value: Date.today, class: "form-control datepicker" %> 
                </div> 
              </div> 
            </div> 
            <div class="form-group"> 
              <div class="btn-group" data-toggle="buttons-radio"> 
                    <div>利用可能 利用不可</div> 
                  <%= f.collection_radio_buttons :status, Calendar.statuses, :first, :first, checked: Calendar.statuses.first do |b| 
                      b.radio_button + b.label { 
                          if (b = "Available") 
                            " " 
                          elsif(b = "Not_Available") 
                                " "                                
                          end 
                          
                          } 
                  end %> 
              </div> 
            </div> 
            <div class="row new-pricing"> 
              <div class="col-md-3"> 
                <div class="form-group"> 
                  <div class="input-group"> 
                    <span class="input-group-addon">1泊</span> 
                    <%= f.text_field :price, class: "form-control", value: @room.price, required: true %> 
                  </div> 
                </div> 
              </div> 
              <div class="col-md-2"> 
                <p style="margin-top: 10px">円</p> 
              </div> 
            </div> 
            <div class="no-pricing hide"> 
            </div> 
            <div class="form-group"> 
              <%= f.button "保存する", type: :submit, class: "btn btn-success" %> 
            </div> 
        <% end %> 
      </div> 
    </div> 
  </div> 
</div> 
<script> 
  $(function() { 
    var notAvailable = $('#calendar_status_not_available'), 
        available = $('#calendar_status_available'); 
    notAvailable.click(function() { 
      $('.no-pricing').show(); 
      $('.new-pricing').hide(); 
    }); 
    available.click(function() { 
      $('.no-pricing').hide(); 
      $('.new-pricing').show(); 
    }); 
  }) 
</script> 



記述追加 app\views\calendars\host.html.erb
19行目に「<%= render 'form' %>」の記述追加
また、複数選択した時に日付が反映されるようにスクリプトを変えています。
コードをコピーしてファイルを置き換えてください。
 
<% if !@rooms.blank? %> 
  <div class="row"> 
    <%= search_form_for @search, class: 'form-group', remote: true, url: host_calendar_path do |f| %> 
      <div class="col-md-6 select"> 
        <div class="form-group"> 
          <label>登録しているお部屋</label> 
          <%= f.select :room_id, options_for_select(@rooms.collect {|u| [u.listing_name, u.id]}, params[:room_id]), {}, { 
            onchange: "$(this.form).submit()", 
            class: "form-control" 
          } %> 
        </div> 
      </div> 
      <%= f.hidden_field :start_date, id: "start-date", value: params[:start_date], onchange: "$(this.form).submit()" %> 
    <% end %> 
  </div> 
<% end %> 
<%= render 'form' %> 
<div id="calendar"></div> 
<script> 
  window.reservations = <%= raw @events.to_json %> 
  window.days = <%= raw @days.to_json %> 
  function showReservations(data) { 
    return data.map(function (e) { 
      if (e['start_date'] !== e['end_date']) { 
         e['end_date'] = moment.utc(e['end_date']).add(1, 'days') 
       } 
      return { 
        name: e.fullname, 
        start: e['start_date'], 
        end: e['end_date'], 
        avatar: e.image, 
        status: e.status 
      } 
    }) 
  } 
  $('#calendar').fullCalendar({ 
    header: { 
      left: 'title', 
      center: '', 
      right: 'prev,next' 
    }, 
    defaultDate: $('#start-date').val(), 
    events: showReservations(reservations), 
    eventRender: function(event, element, view) { 
      return $(` 
        <a class="fc-day-grid-event fc-h-event fc-event fc-start fc-end"> 
          <div class="fc-content ${event.status}"> 
            <span class="fc-title"><img class="img-circle avatar-small" src="${event.avatar}"> ${event.name}</span> 
          </div> 
        </a> 
      `); 
    }, 
    dayRender: function(date, cell) { 
      var dayInfo = $.grep(days, function(e) { 
        return e.day === date.format(); 
      }); 
      console.log(dayInfo); 
      <% if !@rooms.blank? %> 
      if (dayInfo.length > 0) { 
        if (dayInfo[0].status == "Not_Available") { 
          cell.addClass('fc-past'); 
        } else { 
          
          cell.append('<span class="day-price">' + dayInfo[0].price + '円</span>') 
        } 
      } else { 
        cell.append('<span class="day-price">' + '<%= number_to_currency(@room.price) %>' + '</span>') 
      } 
      <% end %> 
    }, 
    selectable: true, 
    select: function(start, end, jsEvent, view) { 
      var start_date = moment(start); 
      var end_date = moment(end).subtract(1, "days"); 
      <% if @rooms.blank? %> 
          $('#calendar').fullCalendar('unselect'); 
      <% end %> 
      var overlap = reservations.filter(function(e) { 
        var r_start_date = moment(e.start_date); 
        var r_end_date = moment(e.end_date).subtract(1, "days"); 
        return (r_start_date.isSameOrBefore(end_date) && r_end_date.isSameOrAfter(start_date)) 
      }).length > 0; 
      if(start.isBefore(moment()) || overlap) { 
        $('#calendar').fullCalendar('unselect') 
      } else { 
        $('#new_calendar').modal('show'); 
        $('#calendar_start_date').datepicker({ 
          dateFormat: "yy-mm-dd", 
          setDate: start_date 
        }); 
        $('#calendar_start_date').val(start_date.format("YYYY-MM-DD")); 
        $('#calendar_end_date').datepicker({ 
          dateFormat: "yy-mm-dd", 
          setDate: end_date 
        }); 
        $('#calendar_end_date').val(end_date.format("YYYY-MM-DD")); 
      } 
    } 
  }); 
  $('.fc-prev-button').click(function() { 
  var current = new Date($('#start-date').val()); 
  var prev = new Date(current.getFullYear(), current.getMonth() - 1, 1) 
  $('#start-date').val(moment(prev).format('YYYY-MM-DD')) 
  $('#start-date').trigger('change') 
}); 
$('.fc-next-button').click(function() { 
  var current = new Date($('#start-date').val()); 
  var next = new Date(current.getFullYear(), current.getMonth() + 1, 1) 
  $('#start-date').val(moment(next).format('YYYY-MM-DD')) 
  $('#start-date').trigger('change') 
}); 
</script> 



記述更新 app\controllers\calendars_controller.rb
3行目からの「create()」メソッド追加、38, 51, 55行目の記述を追加しています。
コードをコピーしてファイルを置き換えてください。
 
class CalendarsController < ApplicationController 

  before_action :authenticate_user! 
  include ApplicationHelper 

  def create 
    date_from = Date.parse(calendar_params[:start_date]) 
    date_to = Date.parse(calendar_params[:end_date]) 
    (date_from..date_to).each do |date| 
      calendar = Calendar.where(room_id: params[:room_id], day: date) 
      if calendar.present? 
        calendar.update_all(price: calendar_params[:price], status: calendar_params[:status]) 
      else 
        Calendar.create( 
          room_id: params[:room_id], 
          day: date, 
          price: calendar_params[:price], 
          status: calendar_params[:status] 
        ) 
      end 
    end 
    redirect_to host_calendar_path 
  end 

  def host 
    @rooms = current_user.rooms 
    params[:start_date] ||= Date.current.to_s 
    params[:room_id] ||= @rooms[0] ? @rooms[0].id : nil 
    if params[:q].present? 
      params[:start_date] = params[:q][:start_date] 
      params[:room_id] = params[:q][:room_id] 
    end 
    @search = Reservation.ransack(params[:q]) 
    if params[:room_id] 
      @room = Room.find(params[:room_id]) 
      start_date = Date.parse(params[:start_date]) 
      first_of_month = (start_date - 1.months).beginning_of_month # 最初の月の1日から 
      end_of_month = (start_date + 1.months).end_of_month # => 3ヶ月後の31日まで 
      @events = @room.reservations.joins(:user) 
                      .select('reservations.*, users.fullname, users.image, users.email, users.uid') 
                      .where('(start_date BETWEEN ? AND ?) AND status <> ?', first_of_month, end_of_month, 2) 
      @events.each{ |e| e.image = avatar_url(e) } 
      @days = Calendar.where("room_id = ? AND day BETWEEN ? AND ?", params[:room_id], first_of_month, end_of_month) 
    else 
      @room = nil 
      @events = [] 
      @days = [] 
    end 
  end 

  private 
    def calendar_params 
      params.require(:calendar).permit([:price, :status, :start_date, :end_date]) 
    end 

end 





この続きはプロジェクトを購入していただくことで見ることができます。
プロジェクトを購入していただくとこのタスクの内容の全てを読みやすい表示で見ることができます。
プログラムコードが色分けされて見やすくなります。
プログラムコードに行番号が付きます。
本文が色分けされて見やすくなります。
そしてプロジェクトを購入するとこのアプリケーションのフルコードをダウンロードすることができます。

まだレビューはありません。

民泊サイトの構築 Rails5.0

2,000円

民泊サイトを構築します。
ホストは部屋を登録し、ゲストは宿泊予約できます。
ゲストはクレジットカードで支払いをし、ホストには料金の80%が自動で口座に振り込まれます。
Googleマップによる表示、AJAX検索、日付カレンダーによる予約、フルカレンダーによる部屋管理ができます。
リアルタイムメッセージにより連絡がとれます。
予約確認メールの送信も可能。
写真のアップロード機能、アマゾンS3の利用方法も解説。
レビュー機能の実装、電話番号認証の実装方法解説。
HEROKUへのデプロイ方法を解説。
フルコードのダウンロード可能。

タスク数: 136