こんにちは、普段はプログラミングスクールでメンターをやっている@takokkeです。
今回はいいね機能の非同期化手順を学習記録としてまとめてみました。axiosなどのjsライブラリを使わず、シンプルにjQueryだけで実装したいと思います
非同期処理の大まかな手順
- いいねボタンを押したら、javascriptリクエストがコントローラに送られる
- アクションがデータ処理を行い、いつもならhtml.erbにインスタンス変数を渡すが、今回はjs.erbへ渡す
- js.erbに記述したjsコードが、いいねボタンの部分だけ書き換える
ポイントは、いつもならコントローラで定義したインスタンス変数がhtml.erbに渡るのを、js.erbに渡すということです。
いいねボタンのHTMLを部分テンプレート化
いいねボタンの部分テンプレートを作成します。
app/views/favorites/_favorite-btn.erb
<% if book.favorited_by?(current_user) %>
<%= link_to book_favorites_path(book.id), method: :delete, remote: true do %>
<i class="fa fa-heart text-danger"><%= book.favorites.count %></i>
<% end %>
<% else %>
<%= link_to book_favorites_path(book.id), method: :post, remote: true do %>
<i class="fa fa-heart text-primary"><%= book.favorites.count %></i>
<% end %>
<% end %>
link_to内にremote; true
を追加することで、
HTMLリクエストではなく、JavaScriptのリクエストがfavoritesコントローラに送られます。
呼び出し元にidを付与しよう
投稿一覧ページなどはidで変更したい部分を指定します。
app/views/books/index.html.erb
:
省略
:
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= link_to book.user do %>
<%= image_tag book.user.get_profile_image(50, 50) %>
<% end %>
</td>
<td><%= link_to book.title,book, class: "book_#{book.id}" %></td>
<td><%= book.body %></td>
<!--いいね機能ajax-partial-->
<td id="favorite_buttons_<%= book.id %>" >
<%= render "favorites/favorite", book: book %>
</td>
<td><p>コメント件数:<%= book.post_comments.count %></p></td>
<td><%= render "books/static_rate", book: book %></td>
</tr>
:
<% end%>
<td id="favorite_buttons_<%= book.id %>" >
でid属性がbookのidによって変わるようにしています。これでいいねボタンを押した部分だけ変更できます。
コントローラで指定しているリダイレクト先を削除
app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
def create
@book = Book.find(params[:book_id]) # インスタンス変数に変更
favorite = @book.favorites.new(user_id: current_user.id)
favorite.save
#redirect_back(fallback_location: root_path)
end
def destroy
@book = Book.find(params[:book_id]) # インスタンス変数に変更
favorite = current_user.favorites.find_by(book_id: @book.id)
favorite.destroy
#redirect_back(fallback_location: root_path)
end
end
リダイレクト先を消すと、リダイレクト先がないかつjavascriptリクエストになります。
これにより
createアクション実行後は、create.js.erbファイルを、
destroyアクション実行後はdestroy.js.erbファイルを探してくれます。
js.erbを作成使用
app/views/favorites/create.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");
app/views/favorites/destroy.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");
以上です