9
7

More than 3 years have passed since last update.

お気に入り機能と一覧の実装

Posted at

備忘録です!!

Bookmarkモデルの作成

ターミナル
rails g model Bookmark user:references board:references
bookmark.rb
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id }

お気に入りを外す処理では、ユーザーと掲示板のお気に入りの関係性がなくなるように該当のレコードを削除します。
もしuserとboardの組み合わせのレコードが重複すると、お気に入りを外しても関係性のレコードが残り、お気に入りが解除できなくなってしまいます。
そのため、ユーザーと掲示板の組み合わせのレコードを一意にするためのunique制約が必要となります。

userモデルとboardモデルのアソシエーション

user.rb
has_many :bookmarks, dependent: :destroy
has_many :bookmark_boards, through: :bookmarks, source: :board
board.rb
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では参照するモデルを指定しています。

ルーティングの追加

routes.rb
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コントローラーの作成

bookmarks_controller
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コントローラーの追加

boards.controller
def bookmarks
  @board = current_user.bookmark_boards.includes(:user).order(created_at: :desc)

ここで、先ほど作成したbookmarksアクションを使います。
book_boardsは、has_namy throughオプションにより、直接アソシエーションでお気に入りした投稿を取得しています。

Viewの追加

今回は、お気にりした時、お気に入りされていない時、お気に入りされているのかを出し入れの3つに分けてパーシャルを作成します。

_bookmark.html.erb
<%= link_to board_bookmarks_path(board.id), id: "js-bookmark-button-for-board-#{board.id}", method: :post do %>
  <%= icon 'far', 'star' %>
<% end %>
_unbookmark.html.erb
<%= link_to board_bookmarks_path(board.id), id: "js-bookmark-button-for-board-#{board.id}", method: :delete do %>
  <%= icon 'fas', 'star' %>
<% end %>
_bookmark_area.thml.erb
<% 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?を用い、お気に入りボタンを出し入れしています。

_board.html.erb
<% 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 %>

自分の投稿には、お気に入りボタンを出ないようにします。

bookmarks.html.erb
<% 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>

お気に入り一覧を表示していきます。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7