Rails ブックマークの実装part2

part1からの続き 中間モデルを定義したので
ルーティング→コントローラ→viewと実装していきます。

ルーティングの設定

BoardモデルとBookmarkモデルが紐付いてるので、ルーティングをネストする必要がある。
commentsとbookmarksコントローラはboardsコントローラにネストしている。

 Rails.application.routes.draw do
  root to: 'static_pages#top'
  get '/login', to: 'user_sessions#new'
  post '/login', to: 'user_sessions#create'
  delete '/logout', to: 'user_sessions#destroy'
  resources :users
  resources :boards do
    resources :comments, only: %i[create], shallow: true
    collection do
      get :bookmarks
    end
  end
  resources :bookmarks, only: %i[create destroy]
end

collectionについて
resourcesで定義されたアクション以外で別のアクションを追加する時に使用する。
今回は、boards_controllerにbookmarksアクションを使えるようにしている。
上記画像のbookmarks_boards GET /boards/bookmarks(.:format) boards#bookmarksこの部分ができる。
ブックマーク一覧ページを表示する際に使う。

ブックマーク一覧ページを表示するためのアクションを追加

  def bookmarks
    @bookmark_boards = current_user.bookmark_boards.includes(:user).order(created_at: :desc)
  end 

ブックマークを習得する際はN+1問題に注意し、includesメソッドを使用しユーザーを呼び出す。

bookmarks_controllerの実装

viewはいらないのでコントローラだけ作成。

class BookmarksController < ApplicationController
  def create
    board = Board.find(params[:board_id])
    current_user.bookmark(board)
    redirect_back fallback_location: root_path, success: 'ブックマークしました'
  end

  def destroy
    board = current_user.bookmarks.find_by(params[:id]).board
    current_user.unbookmark(board)
    redirect_back fallback_location: root_path, success: 'ブックマークを外しました'
  end
end

redirect_back(HTTP_REFERERが設定されていない場合のリダイレクト先 [, オプション])
redirect_backで直前のページへリダイレクトさせる。
直前のページがない場合はfallback_locationでデフォルトのリダイレクト先を指定。
*この2つはセットで使う

board = current_user.bookmarks.find_by(params[:id]).board

について
current_userに紐付いたbookmarksの掲示板のレコードを取得している。
params[:id]でルーティング/bookmarks/:id(.:format) bookmarks#destroyのbookmarks/:idを取得し、
.board掲示板のレコードを取得している。

viewの実装

ブックマークボタンとブックマーク一覧ページの作成。

bookmark解除ボタン

<%= link_to bookmark_path(current_user.bookmarks.find_by(board_id: board.id)), id: "js-bookmark-button-for-board-#{board.id}", class: 'float-right', method: :delete do %>
  <%= icon 'fas', 'star' %>
<% end %>

current_userに紐づくbookmarksをboard_idが含むものを探し、取得する。 pathはrails routes参照。
bookmark DELETE /bookmarks/:id(.:format) bookmarks#destroy
サーバログからパラメータが拾えてるか確認。

bookmarkボタン

<%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}",class: 'float-right',  method: :post, remote: true do %>
  <%= icon 'far', 'star' %>
<% end %>

同じくpathとパラメータが拾えてるか確認。
bookmarks POST /bookmarks(.:format) bookmarks#create

ブックマークボタンを表示させる

掲示板一覧画面にブックマークボタン★☆を表示させる。
掲示板一覧画面では、ログイン中のユーザが作成した掲示板なら編集、削除アイコンを表示
別のユーザが作成した掲示板なら☆が表示されるようにする。
*イメージ図(meoでログイン中)

掲示板一覧画面へ表示させる

<% if current_user.own?(board) %>
  <%= render 'crud_menus', board: board %>
<% else %>
  <%= render 'boards/bookmark_button', { board: board } %>
<% end %>

user.rbに定義しているown?メソッドを使い、current_userが掲示板のuser_idと一致してるか判定している。
一致してれば編集、削除ボタンを表示、そうでなければ☆が表示される。

ブックマークしてるか判定するパーシャルを作成。

<% if current_user.bookmark?(board) %>
  <%= render 'unbookmark', board: board %>
<% else %>
  <%= render 'bookmark', board: board %>
<% end %>

user.rbで前回作成した、ブックマークしているか判定するbookmark?メソッドを使う。
もし、current_userがブックマークしてたらunbookmark(bookmark解除ボタン)をレンダーする。 そうでなければ、bookmark(bookmarkボタン)をレンダーする。
これで、ブックマークすると「★」解除すると「☆」が実装される。

ブックマーク一覧ページの作成

レイアウトは掲示板一覧ページと同じ
boards_controllerのbookmarksアクションで定義した@bookmark_boardsをレンダーする。

〜
<% if @bookmark_boards.present? %>
  <%= render partial: "board", collection: @bookmark_boards %>
<% else %>
  <p> ブックマーク中の掲示板がありません </p>
<% end %>

_header.html.erbへリンクを追加したら完成。

<li class='nav-item'>
  <%= link_to 'ブックマーク一覧', '/boards/bookmarks', class: 'nav-link' %>
</li>