LoginSignup
22
19

More than 3 years have passed since last update.

【Ruby on Rails】ブックマーク(お気に入り登録、いいね)機能:一方向

Last updated at Posted at 2020-09-08

目標

投稿に対して、ブックマーク(お気に入り登録、いいね)機能を実装します。
bookmark.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

前提

※ ▶◯◯ を選択すると、説明等が出てきますので、
  よくわからない場合の参考にしていただければと思います。

双方向のフォロー機能はこちら

モデルの作成

ターミナル
$ rails g model Bookmark user:references post:references

null: falseを追加し、データベースへの空の保存を防ぐ。

db/migate/xxxxxxxxxxxxxx_create_bookmarks.rb
class CreateBookmarks < ActiveRecord::Migration[5.2]
  def change
    create_table :bookmarks do |t|
      t.references :user, foreign_key: true, null: false
      t.references :post, foreign_key: true, null: false

      t.timestamps
    end
  end
end
ターミナル
$ rails db:migrate

各モデルにそれぞれ追加。

app/models/bookmark.rb
validates :user_id, uniqueness: { scope: :post_id }

補足
上記validatesを追加することで、重複しての登録を防ぎます。
具体的には、ロード中に2度以上連続で登録しようとすることを防ぎます。

app/models/post.rb
  has_many :bookmarks, dependent: :destroy

  def bookmarked_by?(user)
    bookmarks.where(user_id: user).exists?
  end
app/models/user.rb
has_many :bookmarks, dependent: :destroy

補足
bookmarked_by?(user)を追加することで、
既にブックマークしているかを検証します。

コントローラーの作成

ターミナル
$ rails g controller bookmarks
app/controllers/bookmarks_controller.rb
class BookmarksController < ApplicationController
  before_action :authenticate_user!

  def create
    @post = Post.find(params[:post_id])
    bookmark = @post.bookmarks.new(user_id: current_user.id)
    if bookmark.save
      redirect_to request.referer
    else
      redirect_to request.referer
    end
  end

  def destroy
    @post = Post.find(params[:post_id])
    bookmark = @post.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

補足
まずはpost_idを取得し、その後user_idにcurrent_userを紐付けています。
bookmark.present?を挟んでいるのは、2度押しのエラーを回避するためです。

config/routes.rb
  resources :posts, except: [:index] do
    resource :bookmarks, only: [:create, :destroy]
  end

補足
postにネストさせています。

viewの修正

app/views/posts/show.html.erb
<tbody>
  <tr>
    <td><%= @post.user.name %></td>
    <td><%= @post.title %></td>
    <td><%= @post.body %></td>
    <td><%= link_to "編集", edit_post_path(@post) %></td>
    <% if @post.bookmarked_by?(current_user) %>
      <td><%= link_to "ブックマークを外す", post_bookmarks_path(@post), method: :delete %></td>
    <% else %>
      <td><%= link_to "ブックマーク", post_bookmarks_path(@post), method: :post %></td>
    <% end %>
  </tr>
</tbody>

一覧表示させるためには

表示したい場所のコントローラーで下記を記述。
今回はapp/views/homes/mypage.html.erbに表示することとする。

app/views/homes/mypage.html.erb
<table>
  <caption>ブックマーク一覧</caption>
  <thead>
    <tr>
      <th>投稿者名</th>
      <th>タイトル</th>
      <th>本文</th>
    </tr>
  </thead>
  <tbody>
    <% @bookmarks.each do |bookmark| %>
      <tr>
        <td><%= bookmark.post.user.name %></td>
        <td>
          <%= link_to post_path(bookmark.post) do %>
            <%= bookmark.post.title %>
          <% end %>
        </td>
        <td><%= bookmark.post.body %></td>
      </tr>
    <% end %>
  </tbody>
</table>
app/controllers/homes_controller.rb
def mypage
  @bookmarks = Bookmark.where(user_id: current_user.id)
end
22
19
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
22
19