ブックマーク機能の実装(モデル)
<実現したいこと>
♡bookmarkを通さずuserとboardを関連性を維持しつつ、
bookmarkを通してuserとboardのテーブルを関連付ける。
♡コントローラーの記述量を減らすこと、汎用性を高めるためのモデルへの記載をする。
♡掲示板を作ったユーザーがお気に入りをしてしまわないように一意性制約をかける。
中間テーブルを通じてデータのやりとりをしている。
<手順>
①app/models/user.rbへの記載(テーブル同士の関連づけ)
②コントローラーへの記載を減らすため、app/models/user.rbに定義をしておく
③掲示板作成者が自分の掲示板にお気に入りを付けてしまうことを防ぐため、app/models/bookmark.rbに一意性制約をかける
①app/models/user.rbへの記載(テーブル同士の関連づけ)
app/models/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
# has many :boards, through: :bookmarksだが,名前が重複するためbookmark_boardsを用いる
ブックマークをしていないとき→userとboardは繋がっている必要がある。
has many :boards
が必要。
ブックマークをしているとき→
has_many :bookmark_boards, through: :bookmarks, source: :board
through: :bookmarks
= ブックマークを通して`
source: :board = board
を参照する
has_many :boards
としても良いように思われるが、ブックマークをしていないときの記述と被ってしまうため、has_many :bookmark_boardsとする。
②コントローラーへの記載を減らすため、app/models/user.rbに定義をしておく
def bookmark(board)
bookmark_boards << board
# <<で引数を渡した掲示板の情報がbookmark_boardsに入ってる
end
# <<は指定されたオブジェクトの末尾に破壊的に追加できる
# 強制的に追加されて保存もされているのでsaveメソッドがいらない
def unbookmark(board)
bookmark_boards.delete(board)
# ブックマークを通して取得した特定のboardを削除する
end
def bookmark?(board)
bookmark_boards.include?(board)
# ブックマークがboardを含んでいるか
# (ブックマークをしていればbookmark_boardsを通してboardが参照される)
end
③app/models/bookmark.rbに一意性制約をかける
app/models/bookmark.rb
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id }
# 掲示板idと同じユーザidがお気に入り関係にならないよう、一意性制約を付けている
scopeで一意性チェックの範囲を限定している。今回の場合board_id
scopeは複数指定も可能