1
0

More than 1 year has passed since last update.

【Rails】【メモ】simple_calendarを使って日付を押すと新規投稿であればnew,投稿済みであればeditに飛べるリンクを作成

Last updated at Posted at 2022-03-05

環境

  • Mac(12.2.1)
    • MacBook Pro (13-inch, 2020)
    • 2 GHz クアッドコアIntel Core i5
    • 16 GB 3733 MHz LPDDR4X
  • ruby (3.0.0p0)
  • rails (7.0.1)
  • mysql2 (0.5.3)
  • 使用gem
    • devise
    • simple_crendar

はじめに

考えたことを実装し動くことを優先に作成したので、読んでもよく分からないところもあるかもしれません

前提知識

  • simple_clendar
  • pluckメソッド
  • strftimeメソッド

参考にした記事

simple_calendar

strftimeについて

配列の扱い方

whereについて

pluckについて

link_toについて

作成イメージ

image.png

詳細

カレンダー内には投稿記事が表示され、かつ、投稿可能な記事の数は1個だけ
更に日付はリンクとなっており投稿記事の有無により、リンク先が変更されている機能を作ってみた

具体的には

  • 投稿記事をDBに保存し、それをsimple_calendarのカレンダー内に記事を表示
  • カレンダー内の動き
    • 記事の作成・編集・削除はカレンダーの日付をクリックすると専用のページに移行する
      • DB内に投稿記事がない場合:newページのリンクが生成され、リンク先で新規投稿(新規投稿時にカレンダーの日にちと同日の日付が連動して保存)
      • DB内に投稿記事がある場合:editページのリンクが生成され、リンク先で投稿編集と削除(編集時は日時変更はされないように設定)

【Rails】投稿の際、新規投稿であればnew,投稿済みであればeditに飛べるようにlink_toでリンクを生成と表示ができるようにした(1日躓いていた).gif

作成コード一覧

config/routes.rb
Rails.application.routes.draw do

  resources :diaries, only:[:new,:index,:create,:edit,:update,:destroy]
  devise_for :users



app/controllers/diaries_controller.rb
class DiariesController < ApplicationController

  def new
    @diary = Diary.new
    @diaries = Diary.where(user_id: current_user.id)
  end

  def index
    @diaries = Diary.where(user_id: current_user.id).all
  end



  def create
    @diary = Diary.new(diary_params)
    if @diary.save
      flash[:notice] = "保存に成功しました"
      redirect_to action: :index
    else
      flash[:alert] = "保存に失敗しました"
      render 'new'
    end
  end


  def edit
    @diary = Diary.find(params[:id])
  end


  def update
    @diary=Diary.find(params[:id])
    if   @diary.update(diary_params)
      flash[:success] = "保存に成功しました"
      redirect_to request.referer
    else
      flash.now[:alert] = "保存に失敗しました"
      render 'new'
    end
  end

  def destroy
    @diary=Diary.find(params[:id])
    if   @diary.destroy
      flash[:notice]="削除しました"
      redirect_to action: :index
    else
      flash[:alert] = "保存に失敗しました"
      render 'edit'
    end

  end



private
  def diary_params
    params.require(:diary).permit(:diary_content_0,:diary_content_1,:diary_content_2,:created_at,:updated_at).merge(user_id: current_user.id)
  end
end
app/views/diaries/index.html.erb
<%= month_calendar events: @diaries do |date,diaries| %>
<% a=@diaries.where(created_at: date).pluck(:created_at)%>
<% b=a.map{ |i| i.strftime("%Y-%m-%d")}%>
<%b[0]%>
<%date%>
<% c=@diaries.where(created_at: date).pluck(:id)%>
<!--ここで現在のuser_idの選択したカレンダーの日にちの記事のidを取得している-->
<%c[0]%>

<%if b[0].to_s == date.to_s%>
<%= link_to date.day,edit_diary_path(c,diary_day: date) %>
<%elsif%>
<%b[0].to_s != date.to_s%>
<%=link_to date.day,new_diary_path(current_user,diary_day: date)%>
<%else%>
<%=link_to date.day, edit_diary_path(current_user,diary_day: date)%>
<%end%>


  <% diaries.each do |event| %>
    <div>
      <%= event.diary_content_0 %>
      <%= event.diary_content_1 %>
      <%= event.diary_content_2 %>
    </div>
  <% end %>
<% end %>
app/views/diaries/new.html.erb

<%=form_with model: @diary,local: true do |f|%>
<%= f.label :title1 %>
<%=f.text_field :diary_content_0%>
</br>
<%= f.label :title2 %>
<%=f.text_field :diary_content_1%>
</br>
<%= f.label :title3 %>
<%=f.text_field :diary_content_2%>

<% f.label :diary_day %>

<%=f.text_field :created_at,value: (params[:diary_day])%>
</br>

<%=f.submit "投稿する"%>

<%end%>
app/views/diaries/edit.html.erb

<%=form_with model: @diary,local: true do |f|%>
<%= f.label :title1 %>
<%=f.text_field :diary_content_0%>
</br>
<%= f.label :title2 %>
<%=f.text_field :diary_content_1%>
</br>
<%= f.label :title3 %>
<%=f.text_field :diary_content_2%>
</br>

<%=f.submit "投稿する"%>
<%end%>

<%=form_with model: @diary, method: :delete,local: true do |f|%>
<%=f.submit "削除する",class: "btn btn-danger"%>
<% end %>

つまづいたところ

主にindex(カレンダー表記部分)に9割ほどつまづいていた

strftimeメソッドが使える対象

strftimeとは時間の表記(フォーマット)を変換するメソッド
日本表記にしたい時や曜日の表記にしたい時などTimeメソッドや Dateメソッドでよく使われるらしい

今回はリンク生成時にnewかeditのどちらを生成するかの条件分岐を書く際の
必要な材料のひとつとして、今回strftimeを使用した

どのように使用したか

今回使用しているgemはsimple_calendarである
このsimple_calendarで取得されている日付は例えば
2022-03-01
といった年月日のみの日付が使われている

<%= month_calendar events: @diaries do |date,diaries| %>
<%date%>
<%end%>

とすると
image.png

のような日付のフォーマットが表示される

上記のフォーマットを用いて

  • カレンダーの日付と登録した記事の日付と比較して日付が同じであればedit
  • カレンダーの日付と登録した記事の日付と比較して日付が違うのであればnew

といった条件分岐を作成しようと考えた

そこで投稿記事のテーブルにあるcreated_atカラムを
simple_calendarで使われているyyyy-mm-ddの形式に変換して
条件分岐を作成しようと考えた

現状だとcreated_atカラムを取得するとこのような形となる(投稿した記事の取得したcreated_atカラムの情報)
[Tue, 01 Mar 2022 00:00:00.000000000 JST +09:00]

  • 時間の部分が00:00:00.000000000となっているのは記事保存時にsimple_calendarの日時を取得して保存しているため
    • 今回で言う<%= month_calendar events: @diaries do |date,diaries| %> <%date%>のdateの年月日を取得してきて、それを投稿記事のcreated_atに保存しているため

配列の中に上記のフォーマットが取得される
そこでstrftimeメソッドを使用してyyyy-mm-ddのフォーマットに変換しようと考えた

pluckメソッドがどういった動きをしているのか

whereとfind_byを比較したときの動きの違い

試したこと一覧

controllerは下記の設定の上でindex.htmlで試したことを書いていきます

app/controllers/diaries_controller.rb
class DiariesController < ApplicationController



  def index
    @diaries = Diary.where(user_id: current_user.id).all
    @test=Diary.pluck(:created_at)
  end

whereとfind_byを比較したときの動きの違い

find_byで取得したときの値

app/views/diaries/index.html.erb
<%=@diaries.find_by(created_at: date)%>

image.png

#<Diary:0x00007fcd68225a28>
DBから探し出している

whereで取得したときの値

app/views/diaries/index.html.erb
<%= @diaries.where(created_at: date)%>

image.png

ActibeRecordを通してからDBから探し出している(値を取り出しているのではなく、探した結果を表示しているだけ)


pluckで取得したときの値

app/views/diaries/index.html.erb
<%= @diaries.pluck(:created_at)%>

該当するcreated_atの値自体を取り出している

image.png

試したことを考慮した上での日付の変換したときの失敗例と実例

失敗例1:strftimeの使用時「NoMethodError in Diaries#index」

エラー情報
undefined method `[]' for Tue, 01 Mar 2022 00:00:00.000000000 JST +09:00:ActiveSupport::TimeWithZone

app/views/diaries/index.html.erb
<%=@diaries.where(created_at: date).pluck(:created_at).map { |e|  e[0].strftime("%Y-%m-%d")}%>

ここでは配列の中が空であるとのことでした

手順 1. カレンダーの日付(date)の値を用いて、その日付に該当する投稿記事のDBのcreated_atカラムを探し出してみる

app/views/diaries/index.html.erb
<%= @diaries.where(created_at: date).pluck(:created_at)%>

image.png

手順 2. 日付を"%Y-%m-%d"表記にしてみる

app/views/diaries/index.html.erb
<% a=@diaries.where(created_at: date).pluck(:created_at)%>
<%= b=a.map{ |i| i.strftime("%Y-%m-%d")}%>

image.png

手順 3. 日付を配列から取り出す

app/views/diaries/index.html.erb
<% a=@diaries.where(created_at: date).pluck(:created_at)%>
<% b=a.map{ |i| i.strftime("%Y-%m-%d")}%>
<%=b[0]%>

image.png


記事の日付とsimple_calendarの日付が同じ表示になっているかの確認

app/views/diaries/index.html.erb
<%=b[0]%>
<%=date%>

image.png


手順.4 条件分岐を書く

app/views/diaries/index.html.erb



<%if b[0].to_s == date.to_s%>
<%= link_to date.day,edit_diary_path(c,diary_day: date) %>
<%elsif%>
<%b[0].to_s != date.to_s%>
<%=link_to date.day,new_diary_path(current_user,diary_day: date)%>
<%else%>
<%=link_to date.day, edit_diary_path(current_user,diary_day: date)%>
<%end%>
・
・
・

to_sメソッドで文字列に直してから比較してみました

結果

image.png

上記のように条件分岐によって生成したリンクの作成ができました

おわりに

もっといい方法があるかもしれません
もしいい方法があればご助言をいただけると幸いです

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0