I implemented it the following way for emojis, you just have to change it thumbs up emoji:
create vote migration
class CreateVotes < ActiveRecord::Migration[6.1]
def change
create_table :votes do |t|
t.boolean :like, default: false
t.boolean :celebration, default: false
t.references :user, null: false, foreign_key: true
t.integer :voteable_id
t.string :voteable_type
t.timestamps
end
add_index :votes, %i[user_id voteable_id], unique: true
end
end
vote model:
class Vote < ApplicationRecord
belongs_to :user
belongs_to :voteable, polymorphic: true
validates :user_id, uniqueness: { scope: %i[voteable_id voteable_type] }
end
voteable concern as model:
module Voteable
extend ActiveSupport::Concern
included do
has_many :votes, as: :voteable, dependent: :destroy
end
def total(icon)
icon_votes ||= Vote.where("#{icon}": true, voteable_id: id, voteable_type: self.class.name).count
icon_votes
end
end
then in routes add the following to class you want to be voteable:
resources :some_voteable_type do
member do
put :vote
end
...
end
in some_voteable_type model:
class some_voteable_type < ApplicationRecord
include Voteable
# more model code
end
in some_voteable_type controller:
#if you have like dislike you have to add dislike method and dislike route and adjust the logic accordingly
def vote
emoji_symbol = params[:emoji]
vote = Vote.find_or_create_by(voteable_id: @session.id, voteable_type: 'Session', user: current_user)
vote.send(emoji_symbol) ? vote.update(emoji_symbol.to_sym => false) : vote.update(emoji_symbol.to_sym => true)
end
now define _votes.html.slim
in some_voteable_type views. the id #show-session-votes might have to adjusted with when you have several of these on one page.
= link_to vote_backend_session_path(@session.id, emoji: :flash_on), method: :put, remote: true, class: "btn #{@session.active :flash_on} btn-vote btn-xs bg-dark body-text border-white hover-primary" do
i.material-icons-outlined.d-inline.align-middle.me-lg-2 flash_on
span.align-middle.text-white.ms-2 = @session.total(:flash_on)
do = render 'votes'
in your show view.
and then add vote.js.erb
here as well:
$("#show-session-votes").html("<%= escape_javascript(render 'votes') %>");
When you want to reuse vote for different pages you would have to make it a nested route instead.