How to implement a like feature in Ajax in Rails

"How to implement a like function in Rails" introduced how to implement a like function, but this time Will introduce how to implement the like function in Ajax (asynchronous communication). The completed system looks like the following. いいね_Ajax.gif



environment

Premise

- This article has implemented the like function.

Edit index.html.erb

Add remote: true </ b> to the two link_to (method:: delete and method: post). By describing remote: true, processing in Ajax can be executed.

html:index.html.erb


<div class="container">
  <h1>List of articles</h1>
  <table class="table">
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td>
          <% if post.liked_by?(current_user) %>
            <% like = Like.find_by(user_id: current_user.id, post_id: post.id) %>
            <%= link_to like_path(like), method: :delete, remote: true do %>
              <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: red;">
              <span><%= post.likes.count %></span>
            <% end %>
          <% else %>
            <%= link_to post_likes_path(post), method: :post, remote: true do %>
              <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: gray;">
              <span><%= post.likes.count %></span>
            <% end %>
          <% end %>
        </td>
      </tr>
    <% end %>
  </table>
</div>

Template the like function part

Create the following file in the same directory as index.html.erb, copy and paste the like function part.

html:_like.html.erb


<% if post.liked_by?(current_user) %>
  <% like = Like.find_by(user_id: current_user.id, post_id: post.id) %>
  <%= link_to like_path(like), method: :delete, remote: true do %>
    <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: red;">
    <span><%= post.likes.count %></span>
  <% end %>
<% else %>
  <%= link_to post_likes_path(post), method: :post, remote: true do %>
    <span class="glyphicon glyphicon-heart" aria-hidden="true" style="color: gray;">
    <span><%= post.likes.count %></span>
  <% end %>
<% end %>

In order to call the partial template (_like.html.erb), write render </ b> where there was a like function part. Also, describe the id so that you can identify the part where Ajax is processed.

html:index.html.erb


<div class="container">
  <h1>List of articles</h1>
  <table class="table">
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td id="like-<%= post.id %>">  <!--Make it identifiable by id-->

       <%= render "like", post: post %>  <!--Call partial template with render-->

        </td>
      </tr>
    <% end %>
  </table>
</div>

Editing controller

I used to do redirect_back at the end of each action, but when I do redirect_back, it reloads and Ajax doesn't work. Therefore, remove redirect_back.

likes_controller.rb


  def create
    like = Like.new(user_id: current_user.id, post_id: params[:post_id])
    @post = like.post
    like.save
  end

  def destroy
    like = Like.find(params[:id])
    @post = like.post
    like.destroy
  end

Create js file

Since we are sending a js format request by remote: true, we will finally look for the js file with the action name (create or destroy) to execute. Therefore, create a likes folder under app / views /, and create.js.erb and destory.js.erb in that folder.

js:create.js.erb


$("#like-<%= @post.id %>").html("<%= j(render 'posts/like', post: @post) %>");

js:destory.js.erb


$("#like-<%= @post.id %>").html("<%= j(render 'posts/like', post: @post) %>");

Identifies by id and partially rewrites html. That's all there is to it.

Recommended Posts