目的
Railsで作成したアプリに非同期いいね機能を実装する。
開発環境
macOS: Big Sur
Rubyバージョン: 2.6.5
Railsバージョン: 6.0.0
前提
- アプリ
test-app
が作成されている。
【Rails】簡単な投稿アプリの作成 -
devise
が導入されている。
【Rails】ユーザー管理機能(devise)の導入 -
jQuery
が導入されている。
【Rails】iQueryの導入 -
Font Awesome
が導入されている。
【Rails】FontAwesomeの導入
手順
- はじめに
- ルーティングの設定
- Likeモデルの作成
- アソシエーションの設定
- バリデーションの設定
- メソッドの定義
- likesコントローラーの作成
- アクションの定義
- いいねアイコンの表示
- jsファイルの作成
はじめに
今回は非同期でのいいね機能を実装していきます。
工程は多いですが、やっていることは複雑ではないため、初学者さんでもしっかり読めばできる内容かと思います。
ルーティングの設定
それでは早速始めていきます!
まずルーティングをネストさせ、設定します!
Rails.application.routes.draw do
# 省略
resources :posts, do
resources :likes, only: [:create, :destroy]
end
end
Likeモデルの作成
次に下記コマンドでLikeモデル
を作成します。
% rails g model like
今回はどの投稿に誰がいいねしたか
を記録したいので、user_id
とpost_id
をカラムに追加します。
class CreateLikes < ActiveRecord::Migration[6.0]
def change
create_table :likes do |t|
t.references :user, null: false, foreign_key: true
t.references :post, null: false, foreign_key: true
t.timestamps
end
end
end
記述できたらマイグレートします。
% rails db:migrate
以上でモデルは完成です!
アソシエーションの設定
続いてアソシエーションの設定です。
class User < ApplicationRecord
# 省略
has_many :likes, dependent: :destroy
has_many :liked_posts, through: :likes, source: :post
end
class Post < ApplicationRecord
# 省略
has_many :likes, dependent: :destroy
has_many :liked_users, through: :likes, source: :user
end
class Post < ApplicationRecord
# 省略
belongs_to :user
belongs_to :post
end
これでアソシエーションの設定ができました!
バリデーションの設定
次はバリデーションの設定です。
1人が1つの投稿に対して、1つしかいいねをつけられないようにします。
class Like < ApplicationRecord
# 省略
validates_uniqueness_of :post_id, scope: :user_id
end
validates_uniqueness_of
によって、post_id
とuser_id
の組は1組しかできないようになりました。
メソッドの定義
いいねしているか否かという条件分岐の際に使用するメソッドを定義します。
# 省略
def liked_by?(post_id)
likes.where(post_id: post_id).exists?
end
end
whereメソッドを使用し、likesテーブルにpost_id
が存在しているかどうか検索をかけています。
exists?メソッド
は、該当の値があればtrue、なければfalseを返すメソッドです。
likesコントローラーの作成
コントローラーを作成します。
% rails g controller likes
アクションの定義
次にアクションの定義です。
class LikesController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
before_action :post_params, only: [:create, :destroy]
def create
Like.create(user_id: current_user.id, post_id: @post.id)
end
def destroy
like = Like.find_by(user_id: current_user.id, post_id: @post.id)
like.destroy
end
private
def post_params
@post = Post.find(params[:post_id])
end
end
create
とdestroy
アクションを定義していきます。
find_byメソッド
は、複数の検索条件を指定することができるメソッドです。
いいねアイコンの表示
次に部分テンプレートを切り替える部分にidを付与します!
具体的には「id = "like_<%= @post.id %>"」
と記述することで、投稿それぞれ異なるidを付与します。
<div id = "like_<%= @post.id %>">
<%= render partial: "likes/like", locals: { post: @post } %>
</div>
部分テンプレートです。
<% if !user_signed_in? %>
<i class="fa fa-heart like-btn"></i>
<%= post.likes.length %>
<% elsif current_user.liked_by?(post.id) %>
<%= link_to post_like_path(post, post.likes), class: "like-link", method: :delete, remote: true do %>
<i class="fa fa-heart unlike-btn"></i>
<% end %>
<%= post.likes.length %>
<% else %>
<%= link_to post_likes_path(post), class: "like-link", method: :post, remote: true do %>
<i class="fa fa-heart like-btn"></i>
<% end %>
<%= post.likes.length %>
<% end %>
remote: true
を付与することでパラメーターをJS形式で送られ、createアクション後は、create.js.erb
が呼び出されます。
.like-link {
text-decoration: none;
}
.like-btn {
font-size: 1em;
color: #808080;
}
.unlike-btn {
font-size: 1em;
color: #e54747;
}
いいねした時
といいねしていない時
で色を変えまてます。
jsファイルの作成
いいね機能を非同期で行うためのjsファイル
を作成します。
$('#like_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: { post: @post }) %>");
$('#like_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: { post: @post }) %>");
これで非同期でのいいね機能が実装できたと思います。
確認してみてください!
最後に
以上で、いいね機能の実装は完了です。
長くなってしまいましたが、一つ一つ理解していけば実装できると思いますので、ぜひ試してみてください。
では。