railsでいいね機能を作るというと、
likeテーブルを作ってボタンを押される度にレコードを作成しているものが多いと思います。
今回は単純にレコードのlikeカラムを+1する方法で
いいね機能を実装しました。
処理の流れ
- divクリックをjqueryで感知
- 要素のクラスを付け替え > 見た目を変える&再クリック防止
- 数字を+1
- ajaxでrailsコントローラの関数を呼ぶ
- 関数内で+1する
- 正常に終わった場合、コンソールログに”正常終了”と出す
本当はajaxが正常に終わった段階で
クラスの付け替え、数字の加算をしようとしたのですが、微妙にラグが出るのでやめました。
実装
DB構成
osusumes と novels が1対多で繋がっています。
おすすめという1ページにたくさんの小説情報がぶら下がり、
その小説情報のいいねが増えていく感じです。
アクセスして来たみんなが
「その小説いいよね!」といいねして、
いいね数で並び替え、人気の小説ほど上に来る
ということを実装したいと考えています。
画面の情報
osusumes#show画面に、
リレーションしているnovelsを表示しています。
コントローラ&ルーティング
osusumesの画面から飛ぶので、
osusumes_controllerにアクションを追加します。
osusumes_controller.rb
def like
# params[:id]の情報はajaxで送ります。
@novel = Novel.find_by(id: params[:id])
if @novel.like == nil
@novel.update(like: 1)
else
@novel.update(like: @novel.like + 1)
end
end
追加したアクションを呼ぶルートを追加します。
routes.rb
Rails.application.routes.draw do
get "osusumes/get_novel_info"
#このosusumes/likeのルートを追加しました
get "osusumes/like"
resources :comments
resources :novels
resources :osusumes
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root "osusumes#index"
end
javascript(ajax)
application.js
$(document).on('turbolinks:load',function(){
$(".novel-card-like").click(function(){
//クラスの付け替え(クラスで見た目とクリック防止を実装)
$(this).removeClass("fa-heart-o").addClass("fa-heart");
//いいね数プラス1
var old_like_count = parseInt($(this).find(".novel-like-count").text());
$(this).find(".novel-like-count").text(old_like_count + 1);
$.ajax({
//osusumesの画面からurl likeを呼ぶことで、osusumes_controllerのlikeアクションを呼び出し
url: "like",
//novelのidをhtmlにhiddenパラメータで埋め込み
//jqueryでidを取得してintegerに変換して送る
data: { id : parseInt($(this).siblings(".novel-id").text()) },
dataType: "html",
//successをこの書き方すると、この中で$(this)が使える(今回は使わなかった)
success: (data) => {
console.log("正常にいいね完了")
},
error: function(data) {
console.log('いいねをつけるのに失敗しています');
}
});
});
});
参考URL : $(this) inside of AJAX success not working
scss
osusumes.scss
.fa-heart-o{
color: grey;
}
.fa-heart{
color: red;
//クリック防止
pointer-events: none;
}
html(haml)
_novel-card.haml
.fa.fa-heart-o.novel-card-like
%span{class: "novel-like-count"}
- if novel.like != nil
#{novel.like}
- else
0
//novel.idを埋め込み
.novel-id{style: "display:none"}
#{novel.id}
課題
リロードすると何回でもいいね出来てしまう。
同じPC、ipアドレスからは1日1回のみいいね出来るとかそんな感じにしたいかも。
ipアドレステーブルみたいなのを作って、
ipアドレスとnovel.idを格納、
本日中のがあったらlike機能で足すのをやめるとかかな。。