Добавление ajax к кнопке «Мне нравится» в приложении Rails

#ruby-on-rails

#ruby-on-rails

Вопрос:

У меня есть приложение rails с почтовым ресурсом, в котором каждая конкретная запись может понравиться / не понравиться.

я хочу иметь возможность ставить лайки / дизлайки без обновления страницы. Я просмотрел несколько других сообщений SO, и все ответы связаны с Coffeescript,, как я могу решить это с помощью vanilla js?

(Я использую Friendly_id и acts_as_votable драгоценные камни)

Контроллер:

  class PostsController < ApplicationController
    before_action :authenticate_user!, only: [:upvote, :downvote] 
    before_action :set_post, only: [ :show , :upvote, :downvote] 
    respond_to :js, :json, :html

  def upvote
    @post.liked_by current_user
    redirect_back(fallback_location: root_path) 
  end 

  def downvote
    @post.disliked_by current_user
    redirect_back(fallback_location: root_path) 
  end 

end
  

Вид:

  <%= link_to like_post_path(@post), class:"like-btn", method: :put, remote: true do %> 
        <button class="btn btn-warning"> 
          <span><p><i class="fa fa-thumbs-up fa-lg" aria-hidden="true"></i></p></span>
        </button> 
      <% end %> 
      <%= link_to dislike_post_path(@post), class:"dislike-btn", method: :put, remote: true do %> 
        <button class="btn btn-warning"> 
          <span><p><i class="fa fa-thumbs-down fa-lg" aria-hidden="true"></i></p></span>
        </button> 
      <% end %> 
      <span> <%= @post.get_upvotes.size %> </span> 
  

Маршруты:

 resources :posts do
    member do
      put "like" => "posts#upvote"
      put "dislike" => "posts#downvote"
    end 
  end 
  

Модели:

 class Post < ApplicationRecord
  acts_as_votable

  extend FriendlyId
  friendly_id :title, use: :slugged 
end


  class User < ApplicationRecord
  acts_as_voter
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end
  

пожалуйста, дайте мне знать, если вам нужна какая-либо другая информация, спасибо!

Комментарии:

1. Вы также хотите что-то обновить в представлении после того, как пользователь поддержит или понизит оценку публикации?

2. @sahil да, я хотел бы, чтобы <span> <%= [at]post.get_upvotes.size %> </span> чтобы отразить, что сообщение понравилось / не понравилось

3. Что происходит с кнопкой «Не нравится», когда пользователь нажимает на кнопку «Нравится», она отключена или пользователь все еще может нажать «Отключить», а затем количество «нравится» уменьшается?

4. @sahil вторая вещь.. пользователь все еще может нажимать, и количество нажатий уменьшается. В идеале я хотел бы, чтобы была только одна кнопка, ТОЛЬКО «НРАВИТСЯ». И когда пользователь нажимает, количество увеличивается, меняется стиль или что-то в этом роде, а при повторном нажатии количество уменьшается. По сути, поэтому оно никогда не могло опуститься ниже 0. Но я соглашусь на наличие двух кнопок, если проще

5. @sahil отредактировал сообщение … я не создавал метод, но драгоценный камень acts_as_votable поставляется со встроенной функциональностью.

Ответ №1:

Здесь я использую единственный метод, поскольку вы никогда не хотите, чтобы количество лайков опускалось ниже нуля.

Всякий раз, когда пользователю нравится публикация, количество увеличивается на 1, а цвет значка «большой палец вверх» меняется (просто чтобы показать визуальное изменение).

Когда пользователь нажимает на уже понравившуюся публикацию, количество лайков должно уменьшаться на единицу, поэтому мы должны использовать метод unliked_by, предоставляемый gem.

Для реализации этого мы можем использовать файл upvote.js.erb (помните, что имя файла должно совпадать с именем вашего метода контроллера, это упрощает процесс).

Затем в .js.erb файле мы можем смешать ruby с js и получить желаемый результат, как показано в upvote.js.erb файле.

Я добавляю дополнительный класс с именем liked , который изменяет цвет кнопки.

Пожалуйста, обратите внимание: я предполагаю, что у вас есть один пост на странице. Если у вас на странице несколько записей, вам следует добавить идентификаторы в контейнер posts и аналогичным образом изменить js код в upvote.js.erb файле.

posts_controller.rb

   def upvote
    if !current_user.liked? @post
      @post.liked_by current_user
    elsif current_user.liked? @post
      # as the above method can also result nil if he is yet to vote
      @post.unliked_by current_user 
    end
  end 
  

просмотры / сообщения / upvote.js.erb

 <% if current_user.liked? @post %>
 document.getElementsByClassName('like-btn')[0].className = "like-btn liked";
<% else %>
 document.getElementsByClassName('like-btn')[0].className = "like-btn";
<% end %>
document.getElementsByClassName('likes-count')[0].innerHTML="<%= @post.get_upvotes.size %>";
  

просмотр.html.erb

 <!-- Adding a class liked -->
<style>
 .liked {
    color: blue;
  }
</style>
<%= link_to like_post_path(@post), class:"like-btn", method: :put, remote: true do %> 
    <button class="btn btn-warning"> 
      <span><p><i class="fa fa-thumbs-up fa-lg" aria-hidden="true"></i></p></span>
    </button> 
<% end %> 
<span class="likes-count"> <%= @post.get_upvotes.size %> </span> 
  

Комментарии:

1. я этого не пробовал, но должен ли файл vote.js.erb быть с повышенным голосованием.js.erb, чтобы он соответствовал имени действия в контроллере? спасибо, кстати, постараюсь реализовать это сейчас

2. Цвет не меняется, когда нравится, поэтому не уверен, что с этим происходит, но остальное работает. Могу ли я спросить, на что ссылается [0] после getElementByClassName? Большое вам спасибо, это потрясающе

3. Поскольку getElementsByClassName метод предоставляет коллекцию всех элементов, имеющих один и тот же класс, нам нужно указать, с каким элементом из коллекции мы хотим работать. В приведенном выше случае мы хотели изменить атрибут первого элемента в коллекции.

4. Добавляет ли это класс liked к тегу i ?

5. на самом деле я только что удалил класс bootstrap btn-warning, потому что, я думаю, он перекрывал пользовательские стили. у меня был этот класс только в качестве теста, после удаления синий цвет отображался нормально