今回はRailsの非同期いいねの方法について紹介します。
参考記事
https://zenn.dev/odentravel/books/e69a157daeecb3/viewer/b583e5
https://zenn.dev/odentravel/books/e69a157daeecb3/viewer/6d1551
同期いいねの作成
参考記事では、postとuserの紐付けになっていますが、自分はrecruitmentとuserの紐付けになります。
最初にmodelを作成して、dbマイグレイトを行います。
rails g model Favorite user_id:integer recruitment_id:integer
rails db:migrate
次にアソーシエーションの設定をします。
#models/user.rb
class User < ApplicationRecord
#〜省略〜
has_many :favorites, dependent: :destroy
end
#models/recruitment.rb
class Recruitment < ApplicationRecord
#〜省略〜
has_many :favorites, dependent: :destroy
def favorited_by?(user)
favorites.where(user_id: user.id).exists?
end
end
favorited_by?では、誰がいいねしたのかを判別します。
#models/favorite.rb
class Favorite < ApplicationRecord
belongs_to :user
end
これで設定が完了しました。
その次にコントローラーを作成します。
$ rails g controller Favorites
そして、コントローラーを記述します。
内容としては、recruitmentの記事を特定して、ログインユーザーがいいねしたのを保存 or 削除するという処理です。
この時点では、リダイレクトの処理を記述します。
#FavoritesController.rb
class FavoritesController < ApplicationController
def create
@recruitment = Recruitment.find(params[:recruitment_id])
favorite = current_user.favorites.new(recruitment_id: @recruitment.id)
favorite.save
redirect_to recruitment_path(recruitment)
end
def destroy
@recruitment = Recruitment.find(params[:recruitment_id])
favorite = current_user.favorites.find_by(recruitment_id: @recruitment.id)
favorite.destroy
redirect_to recruitment_path(recruitment)
end
end
そしてViewを作成します。
この時、いいね作成は、 method: :post にします。
(自分は間違って、method: :recruitment にしてしまい、エラーが出てしまいました。)
#show.html.erb
<td>
<p class="caption"><%= recruitment.locate %>
<% if @recruitment.favorited_by?(current_user) %>
<%= link_to recruitment_favorites_path(@recruitment), method: :delete, class: "favorite_btn" do %>
♥<%= @recruitment.favorites.count %> いいね
<% end %>
<% else %>
<%= link_to recruitment_favorites_path(@recruitment), method: :post, class: "favorite_btn" do %>
♡<%= @recruitment.favorites.count %> いいね
<% end %>
<% end %>
</p> </td>
これで同期いいねの完成です。
非同期いいねの作成
その次にいよいよ非同期いいねの作成に入ります。
最初にlink_toにremote: trueを追記します。これで非同期通信になります。
#show.html.erb
<td>
<p class="caption"><%= recruitment.locate %>
<% if @recruitment.favorited_by?(current_user) %>
<%= link_to recruitment_favorites_path(@recruitment), method: :delete, remote: true, class: "favorite_btn" do %>
♥<%= @recruitment.favorites.count %> いいね
<% end %>
<% else %>
<%= link_to recruitment_favorites_path(@recruitment), method: :post,remote: true, class: "favorite_btn" do %>
♡<%= @recruitment.favorites.count %> いいね
<% end %>
<% end %>
</p> </td>
その次に、部分テンプレート化します。
#favorite/_favorite.html.erb
<td>
<p class="caption"><%= recruitment.locate %>
<% if recruitment.favorited_by?(current_user) %>
<%= link_to recruitment_favorites_path(recruitment), method: :delete, remote: true, class: "favorite_btn" do %>
♥<%= recruitment.favorites.count %> いいね
<% end %>
<% else %>
<%= link_to recruitment_favorites_path(recruitment), method: :post,remote: true, class: "favorite_btn" do %>
♡<%= recruitment.favorites.count %> いいね
<% end %>
<% end %>
</p>
</td>
そして、表示部分を下記のように書き換えます。
#favorite/show.html
<div id="favorite_btn_<%= @recruitment.id %>">
<%= render 'favorites/favorite', recruitment: @recruitment %>
</div>
次に非同期処理を実現するためのjsファイルを作成します。
#favorite/create.js.erb
$('#favorite_btn_<%= @recruitment.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {recruitment: @recruitment}) %>");
#favorite/destroy.js.erb
$('#favorite_btn_<%= @recruitment.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {recruitment: @recruitment}) %>");
処理の意味としては、ボタンが押された時、favorites/favoriteを再レンダーするという意味になります。
最後リダイレクトの削除と@をつけます。
class FavoritesController < ApplicationController
def create
@recruitment = Recruitment.find(params[:recruitment_id])
favorite = current_user.favorites.new(recruitment_id: @recruitment.id)
favorite.save
end
def destroy
@recruitment = Recruitment.find(params[:recruitment_id])
favorite = current_user.favorites.find_by(recruitment_id: @recruitment.id)
favorite.destroy
end
end
これで非同期いいね機能の完成です。