お気に入り機能の実現
・ハートアイコンとそれに付属する数字の表示
・ハートアイコンを押す前に自分が押していなかったら数字を+1して、押していたのなら-1をする
HTML
<div class="card-show" id="js-card-show" data-user-id="<%= @current_user.id %>" data-book-id="<%= @book.id %>">
# この画面に来た時にユーザーが既にお気に入りしているのか否かで条件分岐
<% if Like.find_by(impression_id: impressions.id, user_id: @current_user.id)%>
<span data-liked="true" data-impression-id="<%= impressions.id %>" class="material-icons hart" >favorite</span>
<span><%= impressions.likes.count %></span>
<% else %>
<span data-liked="false" data-impression-id="<%= impressions.id %>" class="material-icons">favorite</span>
<span><%= impressions.likes.count %></span>
<% end %>
</div>
data-user-id="<%= @current_user.id %>" data-book-id="<%= @book.id %>"
data-で始まる属性は、カスタムデータ属性といって、jquery,JavaScript内で値を取得できる形にしている
data-で始まる属性は、htmlとしての意味はないがJavaScriptやCSSで使うことができる
favoriteアイコンは[こちら]
(https://qiita.com/takish/items/9b65f1dcf36cc242357f)を使用しました
contrller
def show
@book = Book.find(params[:book_id])
@user = User.find_by(id: @book.user_id)
@impressions = @book.impressions
end
model
belongs_to :user
belongs_to :impression
has_many :likes
has_many :likes
user.rb
とlike.rb
が結びついているのはユーザー画面でお気に入りした投稿を観れるようにするため
Jquery
application.html.erbの方にjqueryの読み込みを書いていない場合
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
[【2018年版】jQuery最新の読み込みスクリプト「コピペOK+裏技」]
(https://macoblog.com/jquery-saishin/)
# jquery が使えるように読み込む
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
$(function () {
var userId = $("#js-card-show").data("user-id");
var bookId = $("#js-card-show").data("book-id");
$('.material-icons').on('click', function () {
var self = $(this); // クリックされた要素を代入
var impressionId = self.data("impression-id");
var hasMyLike = self[0].dataset.liked;
if (hasMyLike === "true") {
$.ajax({ // イフ文がtrueの場合
url: '/likes/' + impressionId + '/destroy', // 正しい書き方ではない
type: 'POST', // 送信
dataType: "json", // これ書かなかったら自動推察。この場合はなくても動いたです
timespan: 1000, // 通信のタイムアウトの設定(ミリ秒)
data: { //送るデータのカラムと中身
'_method': 'delete',
'impression_id': impressionId,
'user_id' : userId,
'book_id' : bookId,
}
}).done((data) => { // 成功したら
$(this).removeClass('hart'); // ".hart"をクリックした要素から外す
self.next()[0].innerText = (data.count).toString();
self[0].dataset.liked = false; // html上の`data-liked`をtrueからfalseへ
console.log("success"); // 検証のconsoleで見れる
})
.fail((data) => { // 失敗した時の処理
console.log("fail");
})
.always((data) => { //常に行われる処理
console.log("always");
});
} else { // イフ文がfalseの場合
$.ajax({
url: '/likes/' + impressionId + '/create',
type: 'POST', // POSTが送信、GETが受信
dataType: "json",
timespan: 1000,
data: {
user_id : userId,
impression_id : impressionId,
book_id : bookId,
}
}).done((data) => {
$(this).addClass('hart'); // class="hart"をクリックした要素に加える(.や#はいらない)
self.next()[0].innerText = (data.count).toString();
self[0].dataset.liked = true;
console.log("success");
})
.fail((data) => {
console.log(data);
console.log("fail");
})
.always((data) => {
console.log("always");
});
}
});
});
</script>
var userId = $("#js-card-show").data("user-id");
変数宣言してから代入。data属性を使ってrailsのデータをとってきてそれをjquery内で使える変数に代入
bookIdも同じ
$('.material-icons').click(function () {
ブラウザ上でclass="material-icons"
をクリックした時イベントを起こすための.click
イベント
idの場合は.(ドット)ではなく#を使う
(hasMyLike === "true")
hasMyLikeという変数の中身にtrue
という文字列を入れているので判定するためのtrue
も文字列として確実に認識させるために"で囲んでいる。
ajaxの条件分岐で参考にしました。ずっとfalseにデータが行き続けるのはこれで解決
JavaScript 忘れがちな === と == の違い
https://qiita.com/PianoScoreJP/items/e43d70ec188c6fed73ed
こちらは調べても何もわからなかった時に何か一つでもと思って実装しました☟
非同期通信(Ajax)をするときはタイムアウト処理を必ず入れてほしい(切実)
https://qiita.com/tonkotsuboy_com/items/d1b3cf45ae5135441f9b
def create
user_id = params[:user_id].to_i
book_id = params[:book_id].to_i
impression_id = params[:impression_id].to_i
like = Like.new
like.user_id = user_id
like.book_id = book_id
like.impression_id = impression_id
if like.save
current_like_count = Like.where(book_id: book_id, impression_id: impression_id).size
logger.debug(current_like_count)
success_json_object = {
'count' => current_like_count,
}
render :status => :ok, :json => success_json_object
else
failer_json_object = {'status' => 'failer'}
render :status => :internal_server_error, :json => failer_json_object
end
end
# ライク削除処理
def destroy
impression_id = params[:impression_id].to_i //paramsは文字列なので別の場所で数値化
user_id = params[:user_id].to_i //メソッドの中で数値化できなかった
book_id = params[:book_id].to_i
like = Like.find_by(
impression_id: impression_id,
user_id: user_id,
book_id: book_id
)
logger.debug "#{like.inspect}" // ajaxがログにも影響しているのを確認した名残り
logger.debug "-----------------------------------"
if like
if like.destroy
current_like_count = Like.where(book_id: book_id, impression_id: impression_id).size
success_json_object = {
'count' => current_like_count,
}
render :status => :ok, :json => success_json_object //データがtrueの時jsonとして発動?
end
end
end
end
よんでくれてありがとう