GWに入ってからRailsで新しくアプリを作ってます。
今回は「いいね」機能を実装するにあたって自分の中できちんと整理すべくメモ。
参考にした記事
今回も沢山の方々の記事を参考にさせていただきました。ありがとうございます。
【Rails】Twitterのいいね機能を非同期で実装する方法【Ajax】
Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう!(いいね機能のデモ付)
[Rails]いいね機能の非同期での実装!!!
Likeモデル
今作っているのはユーザー(User)が食べ物(Food)に「いいね」できるという機能をつける、ということで両者を紐付ける役割としてLikeモデルを作ります。
rails g model like user_id:integer food_id:integer
UserとLikeは1対多、FoodとLikeも1対多なので、
has_many :likes
has_many :likes
belongs_to :user
belongs_to :food
とします。
ルーティング
config/routes.rbに下記のように追記します。
post "likes/:food_id/create", to: "likes#create", constraints: {food_id: /\d+/}, as: :likes_create
post "likes/:food_id/delete", to: "likes#delete", constraints: {food_id: /\d+/}, as: :likes_delete
コントローラー
コントローラーも作成します。
rails g controller likes
設定したルーティングで呼び出すアクションをapp/controllers/likes_controller.rbに書きます。
def create
@like = Like.new(user_id: @current_user.id, food_id: params[:food_id])
@like.save
@food = Food.find_by(id: @like.food_id)
@like_count = Like.where(food_id: params[:food_id]).count
end
def delete
@like = Like.find_by(user_id: @current_user.id, food_id: params[:food_id])
@food = Food.find_by(id: @like.food_id)
@like.destroy
@like_count = Like.where(food_id: params[:food_id]).count
end
また、カウントの数字を表示するための一文をボタンを設置するビューのファイルにも書いておきます。
@like_count = Like.where(food_id: params[:food_id]).count
部分テンプレート
今回は「いいね」ボタンを表示する部分テンプレートを作成して、ボタンを設置したいところに挿入するという形を取りました。
部分テンプレートのファイル名は_(アンダーバー)で始める必要があります。
<div class="like_button_on">
<%= link_to "いいね済み", likes_delete_path(food_id: @food.id), {method: "post", remote: true} %>
<%= @like_count %>
</div>
<div class="like_button">
<%= link_to "いいね", likes_create_path(food_id: @food.id), {method: "post", remote: true} %>
<%= @like_count %>
</div>
「remote: true」とすることでjs形式で送ることができます。これにより次に書く非同期での処理ができるようになります。
非同期処理
「いいね」ボタンを押すとボタンの色が変わり、カウントの数字も変わる仕様にするための処理を書いていきます。
$('.buttons_<%= @food.id %>').html("<%= j(render partial: 'likes/like' ) %>");
$('.buttons_<%= @food.id %>').html("<%= j(render partial: 'likes/like' ) %>");
コントローラーで指定したアクションと同じ名前で.js.erbファイルを作ります。
こうすることでアクションが実行されるとこちらのファイルを読み込み、ボタンを押した箇所が再びレンダリングされます。
部分テンプレートの挿入
あとはボタンを設置したいところに、
<div class="buttons_<%= @food.id %>"><%= render partial: 'likes/like' %></div>
と書けばOKです。
ボタンを押すと「いいね」の作成・削除が行われ、その都度指定したdivの中身が書き換えられます。
CSS
.like_button{
background-color: #BDBDBD;
}
.like_button_on{
background-color: #FE2E2E;
}
と指定してあげると押すたびにボタンの色が灰色⇔赤色と変わります。色はお好みでどうぞ。
最後に
実際に作ってみるまで部分テンプレートの使い方や仕組み等を全然理解できていませんでしたが、ほんの少しだけ理解が深まったような気がします。
まだまだ理解できていないことが多いので、今後も手を動かしながら実践していきたいと思います。
毎度のことながら、間違っている箇所等あればご指摘いただければ幸いです。