ブックマーク機能
Bookmarkモデルを生成して制約を追加する
$ rails g model Bookmark user:references board:references`
一意性制約をつける
class CreateBookmarks < ActiveRecord::Migration[5.2] def change create_table :bookmarks do |t| t.references :user, foreign_key: true t.references :board, foreign_key: true t.timestamps # 下記を追加して同じ掲示板に何度もお気に入りするのを防ぐ t.index [:user_id, :board_id], unique: true end end end
その後、$ rails db:migrate
モデルにも同じ内容を追加する
bookmark.rb class Bookmark < ApplicationRecord belongs_to :user belongs_to :board validates :user_id, uniqueness: { scope: :board_id } end
モデルにアソシエーションを追加
user.rb has_many :boards, dependent: :destroy has_many :comments, dependent: :destroy # has_many :bookmarks, dependent: :destroy # has_many :bookmark_boards, through: :bookmarks, source: :board
ルーティングの追加
resources :users, only: %i[new create] resources :boards do resources :comments, only: %i[create update destroy], shallow: true collection do get :bookmarks end end resources :bookmarks, only: %i[create destroy]
bookmarks_controllerの生成
$ rails g controller bookmarks create destroy
bookmark処理と判定する処理をモデルに追加
- コントローラーを圧迫したくないのでモデルに記入
user.rb # <<で引数で渡した掲示板レコードが、中間テーブルに自動的に保存される def bookmark(board) bookmark_boards << board end def unbookmark(board) bookmark_boards.destroy(board) end # bookmarkしているか判定 def bookmark?(board) bookmark_boards.include?(board) end
中間テーブル 中間テーブルは多対多の関係を表現するためのテーブル 中間テーブルを用いた処理(Rails) - Qiita
include?メソッド 引数の掲示板レコードが含まれていたらtrue,そうでなければfalseを返す
コントローラー追記
bookmarks_controller class BookmarksController < ApplicationController def create board = Board.find(params[:board_id]) current_user.bookmark(board) # redirect_backで直前のページに戻す redirect_back fallback_location: root_path, success: t('defaults.message.bookmark') end def destroy board = current_user.bookmarks.find(params[:id]).board current_user.unbookmark(board) redirect_back fallback_location: root_path, success: t('defaults.message.unbookmark') end end
お気に入りした掲示板の一覧表示するためのアクション追加
- includesでN+1 問題対策する Rails で includes して N+1 問題対策 - Qiita
boards_controller.rb def bookmarks @bookmark_boards = current_user.bookmark_boards.includes(:user).order(created_at: :desc) end
viewの設定
お気に入りボタンを用意
views/board/_board.html.erb <% if current_user.own?(board) %> <%= render 'crud_menus', board: board %> <% else %> <%= render 'bookmark_button', board:board %> <% end %>
- <% if current_user.own?(board) %>は以前作成した判定のメソッドを使用している
def own?(object) id == object.user_id end
bookmark_buttonを作成
view/boards/_bookmark_button.html.erb <% if current_user.bookmark?(board) %> <%= render 'unbookmark', { board: board } %> <% else %> <%= render 'bookmark', { board: board } %> <% end %>
- こちらでは以前作成した判定メソッドを使用
def bookmark?(board) bookmark_boards.include?(board) end
お気に入り解除のボタン
view/boards/_unbookmark.html.erb <%= 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 %>
お気に入りするボタン
<%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}",class: 'float-right', method: :post do %> <%= icon 'far', 'star' %> <% end %>
お気に入り一覧画面の作成
views/boards/bookmarks <省略> <!-- 掲示板一覧 --> <% if @bookmark_boards.present? %> <%= render @bookmark_boards %> <% else %> <p><%= t('bookmarks.bookmarks.no_result') %></p> <% end %>