Help us understand the problem. What is going on with this article?

Rails5 とFullCalendarで簡易予約システムの実装

More than 1 year has passed since last update.

はじめに

本記事が自分の書く最初の記事なので若干緊張しております。
不適切な表現、間違い箇所などがありましたご指摘していただけると幸いです。

背景

スペースマーケットさんのクローンサイトを作っていたところ、カレンダーを用いた予約システムを実装する必要があり、fullcalendarを導入。space1.png
※画像はスペースマーケットさんのを利用。
こんなのを実装したい!!

フロー

カレンダー表示(ただし、予約ができる日とできない日の表示は区別 Ajaxでイベント取得)
 ↓
予約したい日をクリック

予約日の保持

予約確定ボタンで予約日の保存

※イベント取得時に全部の日がイベントをもつようにしている。
 予約済みの日だった場合、予約済み、予約できる日は、予約可能日は予約可能というイベントを持たせ、
 イベントに応じて、日の背景色やクリックイベントを変えている。

導入

Rails 5.0.7
gemfileにmomentjs-railsとfullcalendar-railsを記載

Gemfile
  gem 'momentjs-rails', '>= 2.9.0'
  gem 'fullcalendar-rails'

その後bundle install

カレンダーの表示

html
<div id="calendar"></div>
calebder.js
  function yesyes(room_id, plan_id, day = 0) {$('#calendar').fullCalendar({ //カレンダーの表示

    events: { //日ごとの情報をイベントとして取得

      url: '/events.json',
      type: 'GET',
      data: {
        room_id: room_id,
        plan_id: plan_id,
        day: day,

      },
      success: function(){

      },
      error: function() {
        alert('there was an error while fetching events!');
      },
    },

    eventRender: function (event, element, view) { //取得したイベントの見た目の設定、event,element,view にはそれぞれイベントの情報が入っている

      if (view.title.length == 9) {
        var view_m = Number(view.title.slice(5, 8))
      }
      else{
        var view_m = Number(view.title.slice(5, 7))
      }

      if (Number(event.start._i.slice(5, 7)) !=  view_m) {
         // eventの日付がカレンダーが表示されている月ではなかったらイベントを記載しないように
         return false;
      }

      if (event.title.match(/\d/) != null){//予約可能日は数字を含むよう設定したためtrueが予約可能日
        var day = event.start._i
        var target = $(`[data-date=${day}]`)

        $(target[0]).addClass("can_reserve_day")

        $(".fc-event-container").find("can_reserve")
        if(now_reses.indexOf(day) >= 0){//now_resesには現在の選択日が入っている。
          $(event.currentTarget).addClass("selected_day")
          $(target[0]).addClass("selected_day")
          $(element[0]).addClass("selected_day")

        };
      }
    },

    header: {
      left: 'prev',
      center: 'title',
      right: 'next',
    },


    Boolean, default: true,
    showNonCurrentDates: true,
    fixedWeekCount: false,


    eventClick: function(calEvent, jsEvent, view) { //イベントクリック時の挙動

      select_day(calEvent, jsEvent, view)

    },

    eventMouseover: function(calEvent, jsEvent, view) { //イベントマウスオーバー時
      over_day(calEvent, jsEvent, view)

    },

    eventMouseout: function(calEvent, jsEvent, view) {
      out_day(calEvent, jsEvent, view)

    },

  })}

イベントの取得

カレンダーを表示するたびに、ajaxでイベントが取得される。
※イベント取得時に自分なりの制約を多数つけてます

events_controller.rb
def index

    t = Time.new
    plan = Plan.find(params[:plan_id].to_i)
    room = Room.find(params[:room_id].to_i)

    case room.basic_info.reserve_period
    when "三ヶ月先" then
      set_sime = 3
    when "六ヶ月先" then
      set_sime = 6
    when "九ヶ月先" then
      set_sime = 9
    when "十二ヶ月先" then
      set_sime = 12
    else
      set_sime = 0
    end

    year = t.year
    sime = t.since(set_sime.month).strftime("20%y-%m-%d")
    today = t.strftime("20%y-%m-%d")

    @dates = (Date.parse(today)..Date.parse(sime)) ###当日から予約締め切り日までの日付を全取得

    @reserves = Reserve.where(room_id: params[:room_id].to_i) #対象施設の予約情報を取得
    reserve_days = []
    @reserves.each do |re|
      re.reserve_dates.each do |day|
        reserve_days << day.start_date    
      end
    end

    cant_weeks = plan.weeks.map{|w|w.name if w.can == false }.compact  #対象施設の貸出不可曜日の取得
    wd = ["祝日", "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]

    if params[:day].to_i == 0 ##時間貸しは未実装
      @can_re = []
      @can_re << {start: t, title: "時間貸し", class_name: "can_reserve"}
    else ##日がしの場合
      @can_re =[] #成形後の日付をここに入れる
      @dates.each do |day|
        title = #{plan.day_price}~"
        class_name = "can_reserve"
        if reserve_days.include?(day.strftime("20%y-%m-%d")) ##予約被り
          class_name = "cant_reserve"
          title = "予約あり"
        end

        if cant_weeks.include?(wd[day.strftime("%u").to_i]) ##予約不可日
          class_name = "cant_reserve"
          title = "不可"
        end
        @can_re << {start: day, class_name: class_name ,title: title  }
      end
    end

    respond_to do |format|
      format.json
    end
end

jbuilderでfullcalenderで使用できる型にする。
イベントオプション

events/index.json.jbuilder
json.array! @can_re do |re|
  json.title       re[:title]
  json.start       re[:start].strftime("20%y-%m-%d")
  json.className   re[:class_name]
end

あとはイベントクリック時に、クリックされた日を取得して、フォームに差し込めばOK!

参考

fullcarender公式
[Ruby on Rails]FullcalendarのイベントをDBに保存・編集
FullCalendarの日本語化やオプションいろいろ

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away