やりたいこと
Laravelで作成した記事投稿アプリなどにおいて、ユーザーが記事をいいねした際に画面遷移や更新などの同期処理ではなく非同期で反映させたい(ユーザーが一つの記事対していいねできるのは一回までにする)
Table
likesテーブルのmigration
likeがuserとarticleに紐付き、user,articleとlikesが一対多の関係
class CreateLikesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('likes', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
$table->integer('article_id')->foreign('article_id')->references('id')->on('articles')->onDelete('CASCADE');
$table->timestamps();
$table->timestamp('deleted_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('likes');
}
}
Model
articleとlikeのリレーションなど
Article.php
class Article extends Model
{
//Likeとのリレーション
public function likes()
{
return $this->hasMany(Like::class);
}
//いいねされてるかの判定
public function isLiked(){
$like = Like::where('user_id', Auth::id())->where('article_id', $this->id)->first();
if($like !== null){
return true;
}
return false;
}
}
User.php
class User extends Authenticatable
{
use Notifiable;
//Articleとのリレーション
public function articles(){
return $this->hasMany(Article::class);
}
//Likeとのリレーション
public function likes(){
return $this->hasMany(Like::class);
}
}
Like.php
class Like extends Model
{
protected $fillable = [
'user_id', 'article_id'
];
//Userとのリレーション
public function user(){
return $this->belongsTo(User::class);
}
//Articleとのリレーション
public function article(){
return $this->belongsTo(Article::class);
}
}
Route
web.php
Route::post('/article/like/{id}', 'LikesController@like')->name('like');
Controller
簡潔にするためcontrollerに更新などのロジックも書いています
public function like(Request $request){
$article_id = $request->article_id;
$article = Article::findOrFail($article_id);
// 実行ユーザーがいいね済みかどうかの確認
if($article->isLiked()){
// いいね済みであれば解除
$article->likes()->where('user_id',Auth::id())->delete();
} else {
// 未いいねであれば登録
$article->likes()->create(['user_id' => Auth::id()]);
}
$likes_count = $article->likes()->count();
$params = [ 'likes_count' => $likes_count ];
//カウント後のいいね数をjsonで返却
return response()->json($params);
}
記事画面
detail.blade.php
記事に紐づくいいね数を表示
<span class="likes">
<i class="bi bi-hand-thumbs-up like-toggle" article_id="{{ $article->id }}"></i>
<span class="like-counter">{{$article->likes->count()}}</span>
</span>
Ajax
public/js/like/like.js
$(function () {
let like = $('.like-toggle'); //like-toggleのついたiタグを取得し代入。
let article_id;
like.on('click', function () {
let $this = $(this); //this=イベントの発火した要素=iタグを代入
article_id = $this.data('article_id'); //iタグに仕込んだdata-review-idの値を取得
//ajax処理スタート
$.ajax({
headers: {
'X-CSRF-TOKEN' : $('meta[name="csrf-token"]').attr('content')
},
url: '/article/like',
method: 'POST',
data: {
'article_id': article_id //いいねされた投稿のidを送る
},
})
//成功した時の処理
.done(function (data) {
// 返却されたカウント後のいいね数を表示
$this.next('.like-counter').html(data.likes_count);
})
//失敗した時の処理
.fail(function () {
console.log('err');
});
});
});