ブックマーク機能の追加

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
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 %>