Like button Ajax in Ruby on Rails Like button Ajax in Ruby on Rails ajax ajax

Like button Ajax in Ruby on Rails


You can do so in various ways, the simple way goes like this:

Preparations

  1. Include Rails UJS and jQuery in your application.js (if not already done so):

    //= require jquery//= require jquery_ujs
  2. Add remote: true to your link_to helpers:

    <%= link_to "Like", '...', class: 'vote', method: :put, remote: true %>
  3. Let the controller answer with a non-redirect on AJAX requests:

    def like  @content = Content.find(params[:id])  @content.liked_by current_user  if request.xhr?    head :ok  else    redirect_to @content  endend

Advanced behaviour

You probably want to update the "n users liked this" display. To archieve that, follow these steps:

  1. Add a handle to your counter value, so you can find it later with JS:

    <span class="votes-count" data-id="<%= @content.id %>">  <%= @content.get_likes.size %></span>users like this

    Please also note the use of data-id, not id. If this snippet gets used often, I'd refactor it into a helper method.

  2. Let the controller answer with the count and not simply an "OK" (plus add some information to find the counter on the page; the keys are arbitrary):

    #…if request.xhr?  render json: { count: @content.get_likes.size, id: params[:id] }else#…
  3. Build a JS (I'd prefer CoffeeScript) to react on the AJAX request:

    # Rails creates this event, when the link_to(remote: true)# successfully executes$(document).on 'ajax:success', 'a.vote', (status,data,xhr)->  # the `data` parameter is the decoded JSON object  $(".votes-count[data-id=#{data.id}]").text data.count  return

    Again, we're using the data-id attribute, to update only the affected counters.

Toggle between states

To dynamically change the link from "like" to "dislike" and vice versa, you need these modifications:

  1. Modify your view:

    <% if current_user.liked? @content %>  <%= link_to "Dislike", dislike_content_path(@content), class: 'vote', method: :put, remote: true, data: { toggle_text: 'Like', toggle_href: like_content_path(@content), id: @content.id } %><% else %>  <%= link_to "Like", like_content_path(@content), class: 'vote', method: :put, remote: true, data: { toggle_text: 'Dislike', toggle_href: dislike_content_path(@content), id: @content.id } %><% end %>

    Again: This should go into a helper method (e.g. vote_link current_user, @content).

  2. And your CoffeeScript:

    $(document).on 'ajax:success', 'a.vote', (status,data,xhr)->  # update counter  $(".votes-count[data-id=#{data.id}]").text data.count  # toggle links  $("a.vote[data-id=#{data.id}]").each ->    $a = $(this)    href = $a.attr 'href'    text = $a.text()    $a.text($a.data('toggle-text')).attr 'href', $a.data('toggle-href')    $a.data('toggle-text', text).data 'toggle-href', href    return  return