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



# 環境
- 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
https://yuma-studio.net/programming/calendar/#SimpleCalendargem

## strftimeについて

https://stackoverflow.com/questions/41894195/perform-strftime-on-created-at-in-pluck

https://teratail.com/questions/228027

https://pikawaka.com/rails/strftime

https://docs.ruby-lang.org/ja/latest/method/Time/i/strftime.html

## 配列の扱い方

https://qiita.com/may88seiji/items/ce9396a4c267a3d449ae


## whereについて

https://qiita.com/Hal_mai/items/babb19560ace072c99f5

## pluckについて

https://railsdoc.com/page/model_pluck

https://pikawaka.com/rails/pluck

https://coffee-engineer4.com/2021/06/12/%E3%80%90rails%E3%80%91%E3%82%AB%E3%83%A9%E3%83%A0%E3%81%AE%E5%80%A4%E3%82%92%E9%85%8D%E5%88%97%E3%81%AE%E5%BD%A2%E3%81%A7%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AB/

https://qiita.com/dnnnn_yu/items/d76208cdfa6c3383d017

https://spirits.appirits.com/doruby/8829/


## link_toについて
https://udemy.benesse.co.jp/development/system/link-to.html

# 作成イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/14866079-4aa3-ff1e-9eef-5e06c0025840.png)

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

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




![【Rails】投稿の際、新規投稿であればnew,投稿済みであればeditに飛べるようにlink_toでリンクを生成と表示ができるようにした(1日躓いていた).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/5d07c69a-253c-8d70-f474-7df007fd8556.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
```


```ruby: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 %>
```



```ruby: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%>
```

```ruby: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/d0f1ce2c-9eaf-34dc-2d71-28ae494ae8a3.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で取得したときの値
```ruby:app/views/diaries/index.html.erb
<%=@diaries.find_by(created_at: date)%>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/b39441c7-fc25-d2fb-2938-c197b0acc2e4.png)

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

### whereで取得したときの値
```ruby:app/views/diaries/index.html.erb
<%= @diaries.where(created_at: date)%>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/f0be6664-3f41-de28-df71-d73b12216341.png)

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

---

### pluckで取得したときの値
```ruby:app/views/diaries/index.html.erb
<%= @diaries.pluck(:created_at)%>
```

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/2df04717-ce04-e96d-40e5-b608f6ec7371.png)

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

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

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

```ruby: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カラムを探し出してみる

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/c4c458b1-3149-d675-9d78-5503243996dc.png)


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

```ruby: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/0870fb2a-7676-8d40-11cf-d1b37d8c84a5.png)

### 手順 3.　日付を配列から取り出す
```ruby: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/8c40cb87-1320-64e2-b735-8a9d5488fd9b.png)

---

### 記事の日付とsimple_calendarの日付が同じ表示になっているかの確認
```ruby:app/views/diaries/index.html.erb
<%=b[0]%>
<%=date%>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/48c2e40e-f38b-af1b-fc8c-c30f7b17817d.png)

---

### 手順．4　条件分岐を書く

```ruby: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747746/0e7b52b3-04fc-c388-6160-de6e840af424.png)

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


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