今回は、お気に入り機能を非同期通信で行えるように実装していきます。
同期通信での実装方法は以下の記事を読んでみてください。
- 各投稿を部分テンプレートとして切り出す
- 「お気に入りに登録」「お気に入りをはずす」どちらかが押されたら、JavaScriptでビューを置き換える
上記のポイントを意識しながら実装していきます。
お気に入り機能(非同期通信実装)
それぞれの投稿を部分テンプレートとして切り出していきましょう。
_post.html.erbを作成し、index.html.erbと_post.html.erbの記述をしていきます。
以下のように記述しましょう。
# posts/index.html.erb
<% if user_signed_in? %>
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
<%= link_to '投稿ページへ', new_post_path %>
<% else %>
<%= link_to 'ログイン', new_user_session_path %>
<%= link_to '新規登録', new_user_registration_path %>
<% end %>
<div class="post">
<h2>投稿一覧</h2>
<p>↓↓↓</p>
<% @posts.reverse_each do |post| %>
<div>
<%= render 'post', post: post%> ←※部分テンプレートを呼び出す記述に変更
</div>
<% end %>
</div>
投稿を表示する記述を切り取って、部分テンプレートを呼び出す記述に変更します。
# posts/_post.html.erb
<%= post.title %>
<% if user_signed_in? && current_user != post.user %>
<% if current_user.favorite_find(post.id) %>
<%= link_to 'お気に入りをはずす', destroy_favorite_path(post.id), method: :delete %>
<% else %>
<%= link_to 'お気に入り登録する', create_favorite_path(post.id), method: :post %>
<% end %>
<% end %>
部分テンプレートに、先程切り取った記述を貼り付けています。
サーバーを起動して表示が変わらないか確認してみましょう。
rails s
# localhost:3000にアクセスして問題なく表示されるか確認
今まで同期通信で行っていた内容を非同期通信化していきます。
link_toにremote: trueを付与します。
非同期通信では「remote: true」が必要となります。
# posts/_post.html.erb
<%= post.title %>
<% if user_signed_in? && current_user != post.user %>
<% if current_user.favorite_find(post.id) %>
<%# link_toにremote: trueを記述 %>
<%= link_to 'お気に入りをはずす', destroy_favorite_path(post.id), method: :delete, remote: true %>
<% else %>
<%# link_toにremote: trueを記述 %>
<%= link_to 'お気に入り登録する', create_favorite_path(post.id), method: :post, remote: true %>
<% end %>
<% end %>
次にコントローラーの記述を変更します。
redirect_toを削除します。
redirect_toを記述してしまうと、画面遷移が行われてしまい非同期通信ができなくなってしまうからです。
# favorites_controller.rb
class FavoritesController < ApplicationController
def create
Favorite.create(user_id: current_user.id, post_id: params[:id])
end
def destroy
favorite = Favorite.find_by(user_id: current_user.id, post_id: params[:id])
favorite.destroy
end
end
記述することができたら、views/favorites内に「create.js.erb」「destroy.js.erb」を作成しましょう。
作成したファイルに以下の記述をしましょう。
# views/favorites/create.js.erb
alert("非同期通信(create確認)")
# views/favorites/destroy.js.erb
alert("非同期通信(destroy確認)")
挙動を確認してみましょう。
以下のように表示されていれば大丈夫です。
処理の流れとしては、以下のようになります。
- リンクを押す(リクエストが飛ぶ)
- コントローラーで処理を行う
- 〇〇.js.erbがレスポンスとして返る
確認することができたら、投稿の表示を切り替える記述をしていきましょう。
投稿の表示を切り替えるためには、どの投稿なのか判断する情報が必要となります。
まずは、情報として各投稿にidを付与していきます。
index.html.erbの記述を変更しましょう。
# posts/index.html.erb
<% if user_signed_in? %>
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
<%= link_to '投稿ページへ', new_post_path %>
<% else %>
<%= link_to 'ログイン', new_user_session_path %>
<%= link_to '新規登録', new_user_registration_path %>
<% end %>
<div class="post">
<h2>投稿一覧</h2>
<p>↓↓↓</p>
<% @posts.reverse_each do |post| %>
<%# divタグにidを付与 %>
<div id="post_<%= post.id %>">
<%= render 'post', post: post%>
</div>
<% end %>
</div>
idを付与することで、どの投稿を変更するか判断することができるようになります。
ブラウザで確認すると以下のようになっているかと思います。
コントローラーで投稿のidを取得していきます。
# favorites_controller.rb
class FavoritesController < ApplicationController
before_action :post_find # メソッドの呼び出し
def create
Favorite.create(user_id: current_user.id, post_id: params[:id])
end
def destroy
favorite = Favorite.find_by(user_id: current_user.id, post_id: params[:id])
favorite.destroy
end
private
def post_find
# 投稿内容の取得
@post = Post.find(params[:id])
end
end
before_actionを使用して、各アクションに適応させています。
部分テンプレートの表示を変更するために、「create.js.erb」「destroy.js.erb」の記述を変更していきます。
# views/favorites/create.js.erb
document.getElementById("post_<%= @post.id %>").innerHTML = '<%= j(render @post) %>'
# views/favorites/destroy.js.erb
document.getElementById("post_<%= @post.id %>").innerHTML = '<%= j(render @post) %>'
処理の流れとしては以下のようになります。
- document.getElementByIdで今回選択された投稿を取得
- innerHTMLでビューの置き換え
- 置き換える内容は、コントローラーから渡された@post
非同期通信化できましたでしょうか?
ぜひご自身のアプリケーションに実装してみてください。
最後までご覧頂きありがとうございました。
同期通信の記事をまだ見ていない方は、ぜひチェックしてみてください!