はじめに
Ruby on Rails と React を用いてSPAのポートフォリオを作る中でAjaxでいいねボタンを作る必要があったのでその方法をシェアしたいと思います. 細かいcontrollerやmodelの作成については書いておりませんのでご了承ください.
なお, いいねボタンのアイコンにはFont Awesomeを使用します.
【動作環境】
Rails 6.1.4
react-rails の gemを使用
1. Font Awesome からハートマークをインストール
$ yarn add @fortawesome/free-solid-svg-icons
$ yarn add @fortawesome/free-regular-svg-icons
↓公式ページの通りインストール
2. フロント側の実装
import React, { useState } from 'react'
import { faHeart as LikeImage} from '@fortawesome/free-solid-svg-icons'
import { faHeart as UnikeImage } from "@fortawesome/free-regular-svg-icons"
function LikeButton(props) {
const [isLiked, setIsLiked] = useState(props.is_liked)
const [likedNumber, setLikedNumber] = useState(props.liked_number)
const clickLikeButton = () =>{
const getCsrfToken = () => {
const metas = document.getElementsByTagName('meta');
for (let meta of metas) {
if (meta.getAttribute('name') === 'csrf-token') {
return meta.getAttribute('content');
}
}
return '';
}
//以下には適宜ポストするデータを入れる
const data = { like: {user_id: props.user_id, report_id: props.report_id} }
//いいねする, いいねを外すのどちらも処理するため, isLikedに合わせてルーティングを変える
let method_type = ''
let fetch_route = ''
if(isLiked){
fetch_route = '/likes/' + props.report_id
method_type = 'DELETE'
}else{
fetch_route = '/likes'
method_type = 'POST'
}
setIsLiked(!isLiked)
etch(fetch_route,{
method: method_type,
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCsrfToken()
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then((result) => {
if(result[0] == "Successful registration of like" || result[0] == "Success to destroy like")
//成功したときの処理を書く
setLikedNumber(result[1])
}else if(result[0] == "Failed to register like" || result[0] == "Failed to destroy like"){
//失敗したときの処理を書く
}else{
//ログインしていない時の処理を書く
alert("ログインしていないとその操作はできません")
}
}
}
}
let like_button;
if (isLiked){
like_button = <div>
<button onClick={()=>{clickLikeButton()}}>
<FontAwesomeIcon icon={LikeImage} style={{"color": "red"}}/>
</button>
</div>
}else{
like_button = <div>
<button onClick={()=>{clickLikeButton()}}>
<FontAwesomeIcon icon={UnikeImage} style={{"color": "red"}}/>
</button>
</div>
}
return (
<div>
{like_button}
{likedNumber}
</div>
);
}
3. バックエンド側の実装
likes_contorller.rb
class LikesController < ApplicationController
def create
if logged_in?
@like = Like.new(secure_like_infomation)
if @like.save
likes_number = Like.where(report_id: params[:like][:report_id]).count
render :json => ["Successful registration of like", likes_number]
else
render :json => ["Failed to register like", @like.errors.full_messages]
end
else
render :json => ["this operation cannot be performed without logging in"]
end
end
def destroy
if logged_in?
@like = Like.find_by(secure_like_infomation)
if @like.destroy
likes_number = Like.where(report_id: params[:like][:report_id]).count
render :json => ["Success to destroy like", likes_number]
else
render :json => ["Failed to destroy like"]
end
else
render :json => ["this operation cannot be performed without logging in"]
end
end
private
def secure_like_infomation
params.require(:like).permit(:user_id,:report_id)
end
end
終わりに
気になるところなどあればコメントいただければと思います。