はじめに
ブックマークを実装するための忘備録です。
実行環境
- Rails 5.2.3
- Ruby 2.6.4
実装
1. アソシエーション
中間テーブルとしてbookmarksテーブルを作成。
2. モデル
2.1 モデルの作成
$ rails g model Bookmark user:references board:references
マイグレーションファイルに追記をします。
db/migrate
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
重複を防ぐために、複合キーインデックスを使い、unique:trueとします。
データベースへ反映させます。
$ rails db:migrate
2.2 モデルの関連付け
app/model/bookmark.rb
class Bookmark < ApplicationRecord
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id }
end
モデルのバリデーションでも重複を防ぐために、scopeを使ってuniquness制約をつくります。
app/model/user.rb
class User < ApplicationRecord
.
.
has_many :bookmarks, dependent: :destroy
.
.
end
app/model/board.rb
class Board < ApplicationRecord
.
.
has_many :bookmarks, dependent: :destroy
def bookmarked_by?(user)
bookmarks.where(user_id: user).exists?
end
end
ブックマークが既にされているかのメソッドをモデルにbookmarked_by?(user)として定義します。
3. コントローラーの作成
$ rails g controller bookmarks
app/controllers/bookmark_controller.rb
class BookmarksController < ApplicationController
def create
board = Board.find(params[:board_id])
bookmark = board.bookmarks.build(user_id: current_user.id)
if bookmark.save
redirect_to request.referer
else
redirect_to request.referer
end
end
def destroy
board = current_user.boards.find(params[:board_id])
bookmark = board.bookmarks.find_by(user_id: current_user.id)
if bookmark.present?
bookmark.destroy
redirect_to request.referer
else
redirect_to request.referer
end
end
end
3. ルーティングとビューの作成
config/routes.rb
resources :boards do
resource :bookmarks, only: %i[create destroy]
end
app/views/board/index.html.erb
<% if board.bookmarked_by?(current_user) %>
<%= link_to "ブックマーク", board_bookmarks_path(board), method: :post %>
<% else %>
<%= link_to "ブックマークを外す", board_bookmarks_path(@board), method: :delete %>
<% end %>
参考にさせていただいた記事