This article is about adding a voting system to your blog app, where users can vote or not vote an article. We all want to allow users to show their interest and react to an article through voting and also get the article with the highest vote. So let’s get started.
Create the Voting Table
Open your rails app directory and enter the code below in your terminal to add the voting table to your database. This will set the relationship between the vote by each user and the voted article.
rails g model Vote user:references article:references
To add the migration to your schema table run
rails db:migrate
and check your schema table which is added after migrating. Open your vote model which is located in the
app/models/vote.rb
and ensure you have the code below.class Vote < ApplicationRecord
belongs_to :user
belongs_to :article
end
Vote Count
We will use
counter_cache
to get the accumulated votes in our database. It counts the number of votes for each article I like to use it because it helps to reduce the number of database queries. We will also set a uniqueness of a vote per user, this will make sure an article is voted once by a user. Let's add a vote count to our article before adding the counter_cache
.rails g migration add_vote_count_to_articles
open the migration you just generated which is in
db/migrate
and add the following code to your change method then run rails db:migrate
class AddVoteCountToArticles < ActiveRecord::Migration[5.2]
def change
add_column :articles, :votes_count, :integer, null: false, default: 0
end
end
Do not forget to complete the relationship between votes with articles and users in the user and article model and adding the code written below.
has_many :votes
Also, make sure that you have this code in your
config/routes.rb
file resources :articles do
resources :votes
end
Adding votes uniqueness
To make sure an article is voted once by a user add the following code in your vote model, this adds 1 vote per user on an article.
validates :user_id, uniqueness: { scope: :article_id }
At this point let us change our Vote model and add the
counter_cache
to count the number of votes on each article. Our vote model should look like this after adding itclass Vote < ApplicationRecord
belongs_to :user
belongs_to :article, counter_cache: true
validates :user_id, uniqueness: { scope: :article_id }
end
Upvote and Downvote an Article
To vote we need to create our Votes controller by adding the following code
rails g controller votes create destroy
open your votes controller which is in your
app/controllers/votes_controller.rb
and add this code to upvote and downvote an article.class VotesController < ApplicationController
def create
@vote = current_user.votes.new(article_id: params[:article_id])
if @vote.save
redirect_to articles_path, notice: 'Vote added.'
else
redirect_to articles_path, alert: 'You cannot vote twice.'
end
end
def destroy
@vote = Vote.find_by(id: params[:id], user: current_user, article_id: params[:article_id])
if @vote
@vote.destroy
redirect_to articles_path, notice: 'You downvoted an article.'
else
redirect_to articles_path, alert: 'You cannot downvote an article that you did not vote before.'
end
end
end
Creating our vote helpers method for our view
We can easily add our voting methods in our views by creating our vote methods in our application helper in your
app/helpers/application_helper.rb
to detect if our users have voted an article. This will be done by writing the code below. module ApplicationHelper
def upvote_or_downvote_btn(article)
vote = Vote.find_by(article: article, user: current_user)
if vote
link_to('<i class="fa fa-thumbs-down"></i>'.html_safe,
article_vote_path(id: vote.id, article_id: article.id), method: :delete)
else
link_to('<i class="fa fa-thumbs-up"></i>'.html_safe, article_votes_path(article_id: article.id), method: :post)
end
end
end
I added Font Awesome icon just for a visual sign that the article was upvoted and downvoted you can check here on how to add Font Awesome icons to your rails app. Now you can call this method in article views to check for votes on an article.
Display votes count
To get a visual display of your accumulated votes count add the following code in your articles view.
<%= pluralize(@article.votes.count, 'Vote') %>
Now the total number of votes for each article is visible to your users. you can also get the article with the highest by simply adding this code to your article model.
scope :highest_vote, -> { order(votes_count: :desc) }
To get the article with the highest vote all we need is to call
highest_vote
on our article and we get the article with the highest vote.Conclusion
We have finally integrated a voting system to our blog app other features can be added to your blog app to improve user experience on your website. Click here for the GitHub repo for this project. Thanks for reading.