ブックマーク機能の追加
Bookmarkモデルの作成
rails g model Bookmark user:references board:references
def change
create_table :bookmarks do |t|
t.references :user, foreign_key: true
t.references :board, foreign_key: true
t.timestamps
end
add_index :bookmarks, [:user_id, :board_id], unique: true
end
end
rails db:migrateをする
(add_index :bookmarks, [:user_id, :board_id), unique: trueで同じユーザーが複数回ブックマークすることを防ぐ)
バリデーションの設定
class Bookmark < ApplicationRecord
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id }
end
バリデーションは上のように設定します。
user_idとboard_idの組み合わせが一意であるようにするため。
1つの掲示板につきuserは1回のみブックマークできるようにするため
アソシエーション
user.rb
has_many :boards, dependent: :destroy
has_many :bookmark_boards, through: :bookmarks, source: :board
board.rb
has_many :bookmarks_boards, dependent: :destroy
ブックマーク機能
user.rb
def bookmark?(board)
bookmark_boards.include?(board)
end
def bookmark(board)
bookmark_boards << board
end
def unbookmark(board)
bookmark_boards.destroy(board)
end
bookmark? ブックマークされているか?
bookmark ブックマークする
unbookmark ブックマークを外す
コントローラーの作成
rails g controller bookmarks
class BookmarksController < ApplicationController
def create
board = Board.find(params[:board_id])
current_user.bookmark(board)
redirect_back fallback_location: root_path
flash[:success] = "ブックマークしました"
end
def destroy
board = current_user.bookmarks.find(params[:id]).board
current_user.unbookmark(board)
redirect_back fallback_location: root_path
flash[:success] = "ブックマークを外しました"
end
end
redirect_backを使うと直前のページへ戻る
boards_controllerにbookmarksアクションを追加
def bookmarks
@bookmark_boards = current_user.bookmarks_boards.include(:user).order(created_at: :desc)
end
ルーティングの設定
resources :boards do
resources :comments, shallow: true
collection do
get :bookmarks
end
end
resources :bookmarks, only: %i[create destroy]
end
resourcesで定義された7つのアクション以外のアクションを定義するときにcollectionを使う
/boards/bookmarksになる
ボタン作成
お気に入りボタン
<%= 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 %>
お気に入り解除ボタン
<%= 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 %>
ボタンの判定
<% if current_user.bookmark?(board) %>
<%= render 'unbookmark', { board: board } %>
<% else%>
<%= render 'bookmark', { board: board } %>
<% end%>
ボタンをrenderする際に下のメソッドで判定する
def bookmark?(board)
bookmark_boards.include?(board)
end
お気に入り一覧画面の作成
<% if @bookmark_boards.present? %>
<%= render @bookmark_boards %>
<% else %>
<p>No result</p>
<% end %>