備忘録です!!
##Bookmarkモデルの作成
rails g model Bookmark user:references board:references
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id }
お気に入りを外す処理では、ユーザーと掲示板のお気に入りの関係性がなくなるように該当のレコードを削除します。
もしuserとboardの組み合わせのレコードが重複すると、お気に入りを外しても関係性のレコードが残り、お気に入りが解除できなくなってしまいます。
そのため、ユーザーと掲示板の組み合わせのレコードを一意にするためのunique制約が必要となります。
##userモデルとboardモデルのアソシエーション
has_many :bookmarks, dependent: :destroy
has_many :bookmark_boards, through: :bookmarks, source: :board
has_many :bookmarks, dependent: :destroy
has_many :bookmark_boards, through: :bookmarks, source: :board
def bookmark_by?(user)
bookmarks.where(user_id: user.id).exists?
end
ここで、
has_many :bookmark_boards, through: :bookmarks, source: :board
に注目してください。
さらに、
def bookmark_by?(user)
bookmarks.where(user_id: user.id).exists?
end
では、bookmarkにuser_idがあるかないかのメソッドを定義しています。
後に、引数にcurrent_userを入れて、お気に入りボタンの出し入れをします。
has many throughオプションでユーザーがお気に入りした投稿を直接アソシエーションで取得できます。
sourceでは参照するモデルを指定しています。
##ルーティングの追加
resources :boards, only: %i[index new create show edit destroy update], shallow: true do
get :bookmarks, on: :collection
resource :bookmarks, only: %i[create destroy]
end
bookmarksをネストし、さらにcollectionでbookmarksという新しいアクションを作成します。
bookmarks_boards GET /boards/bookmarks(.:format) boards#bookmarks
board_bookmarks DELETE /boards/:board_id/bookmarks(.:format) bookmarks#destroy
POST /boards/:board_id/bookmarks(.:format) bookmarks#create
bookmarksというアクションを呼び出したら、お気に入りした掲示板に一覧が出るようにします。
##bookmarksコントローラーの作成
def create
@bookmark = current_user.bookmarks.build(board_id: params[:id])
@bookmark.save!
redirect_back fallback_location: root_path, success: t('defaults.message.bookmark')
end
def destroy
current_user.bookmarks.find_by(board_id: params[:id].destroy!
redirect_back fallback_location: root_path, success: t('defaults.message.not_bookmark')
end
お気に入りを作成、削除を実装しています。
##boardsコントローラーの追加
def bookmarks
@board = current_user.bookmark_boards.includes(:user).order(created_at: :desc)
ここで、先ほど作成したbookmarksアクションを使います。
book_boardsは、has_namy throughオプションにより、直接アソシエーションでお気に入りした投稿を取得しています。
##Viewの追加
今回は、お気にりした時、お気に入りされていない時、お気に入りされているのかを出し入れの3つに分けてパーシャルを作成します。
<%= link_to board_bookmarks_path(board.id), id: "js-bookmark-button-for-board-#{board.id}", method: :post do %>
<%= icon 'far', 'star' %>
<% end %>
<%= link_to board_bookmarks_path(board.id), id: "js-bookmark-button-for-board-#{board.id}", method: :delete do %>
<%= icon 'fas', 'star' %>
<% end %>
<% if board.bookmark_by?(current_user) %>
<%= render 'unbookmark', board: board %>
<% else %>
<%= render 'bookmark', board: board %>
<% end %>
ブックマークボタンのIDはjs-bookmark-button-for-board-掲示板IDというuniqueな要素に設定しています。
お気に入りの出し入れでは、先ほど作成したboard.bookmark_by?を用い、お気に入りボタンを出し入れしています。
<% if current_user == board.user %>
<div class='mr10 float-right'>
<%= link_to edit_board_path(board.id), id: "button-edit-#{board.id}" do %>
<%= icon 'fa', 'pen' %>
<% end %>
<%= link_to board_path(board.id), id: "button-delete-#{board.id}", method: :delete, data: {confirm: '本当に削除してもよろしいです'} do %>
<%= icon 'fas', 'trash' %>
<% end %>
</div>
<% else %>
<div class='mr10 float-right'>
<%= render 'boards/bookmark_area', board: board %>
</div>
<% end %>
自分の投稿には、お気に入りボタンを出ないようにします。
<% content_for(:title, 'ブックマーク一覧') %>
<div class="container pt-3">
<div class="row">
<div class="col-lg-10 offset-lg-1">
<!-- 検索フォーム -->
<form>
<div class="input-group mb-3"><input class="form-control" placeholder="検索ワード" type="search"/>
<div class="input-group-append"><input type="submit" value="検索" class="btn btn-primary"/></div>
</div>
</form>
</div>
</div>
<!-- 掲示板一覧 -->
<div class="row">
<div class="col-12">
<div class="row">
<% if @board.present? %>
<%= render @board %>
<% else %>
<P><%= t('.no_title') %></p>
<% end %>
</div>
</div>
</div>
</div>
</div>
お気に入り一覧を表示していきます。