いいね機能を作ろう
likesテーブルの役割
「どのユーザー」が「どの投稿」をいいねしたかを記録するために、データベースに「user_id」と「post_id」2つのカラムを持つlikesテーブルを用意しましょう。例えば下の図のように、user_idが1、post_idが2のデータは、「id:1のユーザーがid:2の投稿をいいねした」ということを表します。
likesテーブルを作成しよう
rails g modelrails db:migrate
右の図のコマンドを実行して、Likeモデルとマイグレーションファイルを用意しましょう。likesテーブルにはuser_idとpost_idの2つのデータを持たせるようにしてください。
マイグレーションファイルの用意ができたら「rails db:migrate」を実行して、データベースに反映させましょう。
バリデーションを追加する
validatespresence
いいねのデータは、user_idとpost_idの両方が常に存在していないと不完全なデータとなってしまいますので、最初にバリデーションを追加しておきましょう。user_idとpost_idのそれぞれに、値が存在していることをチェックする「presence: true」のバリデーションを追加します。
■ ターミナルで以下のコマンドを実行してください
rails g model Like user_id:integer post_id:integer
rails db:migrate
like.rb
class Like < ApplicationRecord
validates :user_id, {presence: true}
validates :post_id, {presence: true}
end
「rails console」でデータを作成する
newsaverails console
コンソールでlikesテーブルにデータを追加してみましょう。「Like.new(user_id: 1, post_id: 2)」とすることで、「idが1のユーザーが、idが2の投稿にいいねした」というデータを作成することができます。
■ ターミナルで以下のコマンドを実行してください
rails console
■ コンソールで以下のコマンドを実行してください
like = Like.new(user_id: 1, post_id: 2)
like.save
quit
「いいね!済み」と表示する条件
投稿詳細ページでは、「ログインしているユーザーがその投稿にいいねしたデータが存在する」という条件を満たす場合、「いいね!済み」と表示するようにしましょう。
逆に、この条件を満たしていない場合には「いいね!していません」と表示しましょう。
条件分岐
find_by
「ログインしているユーザーがその投稿にいいねしたデータが存在する」という条件のために、user_idとpost_idが合致するデータがlikesテーブルに存在するかどうか、find_byを用いてチェックします(find_byは該当するデータが見つからなかった時にnilを返すことを思い出しましょう)。
show.html.erb
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
いいね!済み
<% else %>
いいね!していません
<% end %>
いいねボタンの準備
likesコントローラを用意しよう
今までコントローラは「rails g controller」コマンドで自動生成してきました。コマンドを用いるとビューファイルなども自動生成されますが、今回はそれらのビューファイルが必要ないので、コントローラを手動で作ってみましょう。controllersフォルダ内に「likes_controller.rb」というファイルを新規作成し、右の図のように大枠を記述するだけで作ることができます。
routes.rb
# createアクションに対応するルーティングを追加してください
post “likes/:post_id/create” => “likes#create”
likes_controller.rb
class LikesController < ApplicationController
# before_actionに「:authenticate_user」を追加してください
before_action :authenticate_user
# createアクションを追加してください
def create
end
end
いいねボタンを作ろう
createアクションを完成させよう
newsave
それではcreateアクションの中身を完成させましょう。
createアクション内では新たにデータを作成後、投稿詳細ページへとリダイレクトさせます。
user_idは@current_userから、post_idはparamsから取得して作成しましょう。
createアクションへのリンクを用意しよう
link_to
作成したcreateアクションへのリンクを投稿詳細ページに追加しましょう。
下の図のように、今までは「いいね!していません」と表示していた部分を、「いいね!」するためのリンクに書き換えます。
likes_controller.rb
def create
# 変数@likeを定義してください
@like = Like.new(
user_id: @current_user.id,
post_id: params[:post_id]
)
# 変数@likeを保存してください
@like.save
# 投稿詳細ページにリダイレクトしてください
redirect_to("/posts/#{params[:post_id]}")
end
show.html.erb
<%= link_to("いいね!", "/likes/#{@post.id}/create", {method: "post"}) %>
いいね取り消しボタンを作ろう
destroyアクションを用意しよう
find_bydestroy
「いいね!」を取り消す機能を作るために、まずはlikesコントローラにdestroyアクションを作成しましょう。destroyアクション内では、受け取った@current_user.idとparams[:post_id]をもとに削除すべきLikeデータを取得し、destroyメソッドを用いて削除します。
routes.rb
# destroyアクションに対応するルーティングを追加してください
post “likes/:post_id/destroy” => “likes#destroy”
show.html.erb
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
<%= link_to("いいね!済み", "/likes/#{@post.id}/destroy", {method: "post"}) %>
<% else %>
likes_controller.rb
# destroyアクションを定義してください
def destroy
@like = Like.find_by(user_id: @current_user.id, post_id: params[:post_id])
@like.destroy
redirect_to(“/posts/#{params[:post_id]}”)
end
いいねボタンをアイコンにしよう(1)
Font Awesomeとは
「Font Awesome」とは、様々なアイコンをフォントとして利用できるようにしたものです。
HTML & CSS 学習コース 中級編でも用いたので、忘れてしまった場合は復習をしておきましょう。
Font Awesomeの読み込み
「Font Awesome」を利用するには、
タグなどの共通のHTMLはapplication.html.erbに書きますので、
今回はそこに読み込み用のタグを追加しましょう。
ハートアイコンの表示
左の図のようにに「fa fa-heart」というクラス名をつけることで、ハートアイコンを表示することができます。しかし、右の図のようにlink_toメソッド内にHTML要素を記述すると正しく表示することができません。
HTML要素に対してlink_toメソッドを使う方法を次のスライドで見てみましょう。
HTML要素に対して
link_toメソッドを使う
link_todo
HTML要素に対してlink_toメソッドを使うには、少し異なる書き方をする必要があります。
右の図のように、<%= link_to(URL) do %>と<% end %>の間にHTML要素を書くことで、その部分をリンクにすることができます。
ink_toメソッドで
ハートアイコンを表示する
link_todo
link_toメソッドでハートアイコンを表示してみましょう。
下の図のように、<%= link_to("URL") do %>と<% end %>の間にを書き、「fa fa-heart 」というクラス名をつけることでハートアイコンのリンクを作ることができます
show.html.erb
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
<%= link_to("/likes/#{@post.id}/destroy", {method: "post"}) do %>
<% end %>
<% else %>
<%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %>
<% end %>
posts.scss
// .like-btnのcolorを「#8899a6」にしてください
.like-btn {
color: #8899a6;
}
// .like-btn-unlikeのcolorを「#ff2581」にしてください
.like-btn-unlike {
color: #ff2581;
}
// ここに指定されたCSSを貼り付けてください
.posts-show-item .fa {
font-size: 16px;
margin-right: 3px;
}
countメソッド
count
likesテーブルからデータの件数を取得するには、countメソッドを用います。countメソッドは配列の要素数を取得するメソッドですが、テーブルのデータ数を取得するためにも利用することができます。
show.html.erb
<%= @likes_count %>
posts_controller.rb
def show
@post = Post.find_by(id: params[:id])
@user = @post.user
# 変数@likes_countを定義してください
@likes_count = Like.where(post_id: @post.id).count
end
いいねした投稿を表示しよう(1)
likesアクションを用意する
「いいね!」をした投稿を一覧で表示するために、likesアクションをusersコントローラ内に作成しましょう。
ルーティングのURL部分はshowアクションと同様に、どのユーザーに関する情報を表示するかを判断するために「users/:id/likes」とします。
# “users/:id/likes”に対応するルーティングを追加してください
get “users/:id/likes” => “users#likes”
users_controller.rb
# likesアクションを追加してください
def likes
end
show.html.erb
- <%= link_to("投稿", "/users/#{@user.id}") %>
- <%= link_to("いいね!", "/users/#{@user.id}/likes") %>
likesアクションを完成させよう
where
ビューで用いる変数をアクション内で定義しましょう。
whereメソッドを用いてそのユーザーに関するデータをlikesテーブルから取得し、変数@likesに代入します。
likesアクションのビュー
find_by
likesアクション内で定義した変数@userと@likesを用いて、ビューも完成させましょう。
各投稿を1つずつ表示するためには、@likesに対してeach文を用いて、likeに紐付いているpostを表示させます。
users_controller.rb
def likes
# 変数@userを定義してください
@user = User.find_by(id: params[:id])
# 変数@likesを定義してください
@likes = Like.where(user_id: @user.id)
end
likes.html.erb
<% @likes.each do |like| %>
<% post = Post.find_by(id: like.post_id) %>
<%= link_to(post.content, "/posts/#{post.id}") %>
<% end %>