【Rails】いいね機能index追加(resourceからresoucesへの変更)

# はじめに
先日、いいね機能を実装した。↓

https://qiita.com/vaza__ta/items/c0bc7f590793ab5a4769

showテンプレートにいいねしたユーザー一覧を表示するようにしていたが、indexテンプレートを実装するよう変更する。

その際にroutes.rbでresource=>resourcesに変更した。
これにより、ルーティングの変更が発生するため、その修正すべき部分を解説していく。

# 前提
下記のテーブルは作成済み。
users(ユーザー)
posts(投稿)
favorites(いいね)
| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |       Ruby      |   2.6.3   |
| 3  |       rails      |      6.0.4 |

# ルーティングを修正する
indexを追加するために、resouceをresourcesに変更する。
**resource:** 
・index以外のRESTに準拠したルーティングを生成できる。
・pathはidを含める必要がない。
**resources:**
・indexを含む全てのRESTに準拠したルーティングを生成できる。
・:edit, :show, :update, :destroyアクションの pathにidを含める必要がある。

```routes.rb
  # resources :posts do
    # resource :favorites, only: [:show, :create, :destroy]
# 下記に変更
  resources :posts do
    resources :favorites, only: [:index, :create, :destroy]
```
```言語名:ターミナル
$ rails routes
# ルーティング変更前
# post_favorites GET    /posts/:post_id/favorites(.:format)  favorites#show
#                DELETE /posts/:post_id/favorites(.:format)  favorites#destroy
#                POST   /posts/:post_id/favorites(.:format)  favorites#create

# ルーティング変更後 (showとdestroyが「post_favorite_path」になったことに注意)
post_favorites GET    /posts/:post_id/favorites(.:format)　　　　　　　　　　favorites#index
               POST   /posts/:post_id/favorites(.:format)　　　　　　　　　　favorites#create
post_favorite 　　DELETE /posts/:post_id/favorites/:id(.:format) favorites#destroy
```
これでindexを作成可能となり、destroyアクションでfavoriteテーブルの:idが必要となる。

# いいね機能周りの修正
いいね取り消し（destroy）で@favoriteが必要となる。
いいねをすると、次に取り消しボタンが表示されるため、そこで@favorite
が必要になる。よって、createアクションに実装する。
```favorites_controller.rb
  def index
    @post = Post.find(params[:post_id])
    @favorite_users = @post.favorite_users
  end

# favorite　をインスタンス変数@favoriteに修正した。
  def create
    @post = Post.find(params[:post_id])
    @favorite = current_user.favorites.create(post_id: @post.id)
    @favorite.save
    @favorite_users = @post.favorite_users
    respond_to do |format|
      format.html { redirect_to @post }
      format.js 
  end
```

いいねを押した時に反応したjsファイルを修正する。
```app/views/favorites/create.js.erb
# favorite: @favoriteを追加する
$("#favorite_icon_<%= @post.id %>").html("<%= escape_javascript(render('favorites/favorited_state', post: @post, favorite: @favorite)) %>");
```
いいねを押した後に、上記によりレンダリングされるパーシャルを修正する。
いいねを押した後はいいね取り消しのための情報が必要である。
取り消しには、favoriteテーブルの該当idを取得し、それを使ってdeleteリクエストを投げればよい。
```app/views/favorites/_favorites_state.html.erb
# post_favorite_pathに修正と、favorite.idを追加
<%= link_to post_favorite_path(post.id, favorite.ids), class: "btn", method: :delete, remote: true do %>
  <i class="fa-solid fa-thumbs-up fa-3x"></i>
<% end %>
```

# 投稿機能周りの修正
favoriteの:id情報を取り込む。
投稿記事のshowコントローラーと、showページに@favoriteを追加する。
```posts_controller.rb
def show
    @post = Post.find(params[:id])
# 下記を追加
    @favorite = Favorite.find_by(post_id: @post.id)
...
end
```
```app/views/posts/show.html.erb
...
<%# いいね機能 %>
<span id="favorite_icon_<%= @post.id %>">
  <% unless current_user?(@user) %>
    <% if @post.favorited?(current_user) %>
# @favoriteを追加
      <%= render 'favorites/favorited_state', post: @post, favorite: @favorite %>
    <% else %>
# @favoriteを追加
      <%= render 'favorites/unfavorited_state', post: @post, favorite: @favorite %>
    <% end %>
  <% end %>
</span>
...
  <%= link_to "いいねしたユーザー", post_favorites_path(@post) %>
# => app/views/favorites/index.html.erb
...
```

# いいねしたユーザー一覧のindexテンプレートを作成する
index.html.erbを作成し、内容を書いていく。(show.html.erbに書いてた内容を移すだけ。) 
```app/views/favorites/index.html.erb
<ol id="favorite_user">
  <%= render partial: 'favorites/favorite_user', favorite_users: @favorite_users %>
</ol>
<%= link_to :back do %>
  <button class="btn margin-top">BACK</button>
<% end %>
```
# 完成
![favorite いいね追加.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/8c69d294-6b1b-8b6d-f6dc-ff269d9e0838.gif)

# おわりに
resource を resources に変更するだけで、かなりの工数を使った。
基本的には、indexをつくる気がなくても、resourcesでルーティングを書いた方がいいのかもしれない。
pathに対して、idを渡す必要が出てきてしまうが、そこはトレードオフになる。