Naomi's notebook

Naomi's notebook

Ruby on Rails tutorial +alpha(2)カレンダーを表示する

注意:この記事はメモなので、この記事に書いてあることをやっただけでは同じものができないかもしれません。(大体の雰囲気は書いてあると思います。) 注意:全くのweb開発初心者なので、間違っているところなどがあるかと思いますが、教えていただけると嬉しいです。

書いていなかったと思いますが、カレンダーを表示して、そこで何か生活習慣を整えられるようなアプリを作りたいので、まずはカレンダー上に睡眠状況が表示できるようにします。

git checkout -b add_calendar

カレンダーの表示

調べたところsimple calendarというgemが存在するらしいので(なんでもありますね…)それを使おうと思ったのですが、やってみたところ一週間を大きく表示したり時間毎の予定の表示なんかはできないみたいです。のでfullcalendarを使います。

github.com

readmeを読んでその通りにやったのですが、カレンダーが出ない… asserts/javascripts/application.jsがrails 6では存在しないようです。

う〜ん。(色々やってみたけどうまくいかなかった) まあ練習代わりにも、以下のようなものを参考にjQueryで書くことにしました。

fullcalendar.io stackoverflow.com

yarn add @fullcalendar/core @fullcalendar/daygrid @fullcalendar/list

app/javascript/packs/application.js

window.Calendar = require("@fullcalendar/core").Calendar;
window.dayGridPlugin = require("@fullcalendar/daygrid").default;
window.listPlugin = require("@fullcalendar/list").default;

app/javascript/stylesheets/application.scss

@import '../node_modules/@fullcalendar/core/main.css';
@import '../node_modules/@fullcalendar/daygrid/main.css';
@import '../node_modules/@fullcalendar/list/main.css';

views/layouts/~~~

<div id="calendar"></div>

...
<script>
  $(function() {
    var calendarEl = document.getElementById('calendar');
    var calendar = new Calendar(calendarEl, {
      header: {
        left: 'prev,next',
        right: 'dayGridMonth, listMonth'
      },

      plugins: [ dayGridPlugin, listPlugin ],
      defaultView: 'dayGridMonth'
    });

    calendar.render();
  });
</script>

みられました。 使用目的としては時間でグリッドされたカレンダーを見せたいですね。 TimeGrid View - Docs | FullCalendar timegridを追加すればできます。

イベントモデルの作成

次は日付・時間にそって睡眠記録などが表示されるようにします。 まず、イベントというモデルを作ります。

 rails generate model Event type:integer title:text starttime:datetime endtime:datetime user:references

要件としては、

  • Titleはnullでも大丈夫、20文字以内(適当)
  • typeはnullでも大丈夫(特に制限がない)
  • starttime,endtime,user_idはnilではいけない
  • starttime<endtimeである

です。 また、user_idとstarttime,endtimeで検索することが多いので、userとstarttime,endtimeにインデックスをつけておきます。

class Event < ApplicationRecord
  belongs_to :user
  validates :user_id, presence: true
  validates :title, length: { maximum: 20 }
  validates :starttime, presence:true
  validates :endtime, presence:true
  validate  :end_day_is_after_start_day

  def end_day_is_after_start_day
    errors.add(:end, "はstartより後の日時を指定してください") if starttime==nil || endtime==nil || starttime > endtime
  end
end

ところでこれ、タイムゾーンが東京ではないのでめんどくさそうですね…国際化は後で考えるとして、とりあえずconfig.time_zone = 'Tokyo'をapplication.rbに追加しておきました。

また、userの方にもhas_many :events, dependent: :destroyを追加しておきます。

次に適当に有効性testを書きます。テストを書いているとエラーが出ました。

ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: '1'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Event.inheritance_column to use another column for that information.

どうやらtypeという名前はすでにrailsによって使われているからダメみたいですね。eventtypeに改名して進めました。

jsonでの出力・

jsonを渡すとカレンダー上でイベントを表示できるということで(Event Object - Docs | FullCalendar)、そのjsonをuser.eventsから作ってもらうことにしましょう。

次に、users/(user_id)/event/にアクセスすると、jsonでイベント情報を出すようにします。

Users_contoroller.rbに

def events
    @title = "Events"
    @user  = User.find(params[:id])
    @events = @user.events
    render 'events',formats: :json , handlers: 'jbuilder'
  end

を追加します。formats: "json"にするとrails5以前では動くようですが、rails6ではArgumentError: Invalid formats: "json" エラーになるので注意してください。

あとはこれをカレンダーに読ませれば完了です。(詳しくはFullcalender.ioのページを見てください。)

events: <%=@user.id%>+"/events"

できたもの f:id:Naomi_Lilienthal:20200814165558p:plain

次回予告

以下のような改善を今の所は考えています。 今後はブログに書くのは、書いても支障がなさそうなものを選んで書くことにします。

機能として必ず必要なもの

  • 当たり前ですが、eventを作成する画面を作る(とりあえずフォームで、それができたらもっと優れたやりやすい方式で)
  • eventを後から変更する画面を作る

使いやすさの面で必要そうなもの

  • eventをタイマーなどでリアルタイムに作成できるようにする(studyplusアプリのアレみたいなイメージです)
  • カレンダー上の予定をクリックすると編集画面が出てくる

個人情報の扱い的に正しそうなもの

  • ログインした時やフォローされている時しかevents/(user_id)/eventsでjsonデータが返されないようにした方が個人情報的には良さそうです
  • 上に付随して、フォローされるのを許可制にできるようにする
  • 誰にでも見せられる設定にしている時、userのプロフィール画面に簡単にはアクセスできないようにする(アドレスを複雑にする)ことでアドレスを知っている人にだけ記録が見せられるようにする

スケーリングのために必要そうなこと

  • fullcalendarが/users/(user_id)/eventsにアクセスするときに全てのuser.eventsを取得するのではなく、endtimeがstartより後、またはstarttimeがendより前のもののみ取得する(whereとかを使えそう)

その他