目標
投稿に対して、ブックマーク(お気に入り登録、いいね)機能を実装します。
開発環境
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