In this post I want to show to add upvotes and dowvotes using acts_as votable gem.
What do You Need
- Basic Authentication with current_user helper(Devise or something else)
- One model with name Link and controller links
- acts_as_votable gem installed
How to setup acts_as_votable
Add gem acts_as_votable to your Gemfile.
Gemfile
'acts_as_votable'
And install it with bundle
bundle install
Now generate acts_as_votable migration
rails generate acts_as_votable:migration
And migrate to database
rake db:migrate
Now we’re done with preparation let’s add upvote action.
Adding upvotes
First thing we need to is to add acts_as_votable helper to our model.
app/models/link.rb
class Link < ActiveRecord::Base
acts_as_votable
end
Helper will provide useful methods like this:
upvote_by ..... => Add upvote by current_user
get_dislikes.size => Count all downvotes
get_likes.size => Count all upvotes
You can checkout all methods at acts_as_votable documentation.
So now when we know how acts_as_votable can helps us, let’s add upvoting to our controller.
app/controllers/links_controller.rb
def upvote
@link = Link.find(params[:id])
@link.upvote_by current_user
redirect_to links_path
end
config/routes.rb
resources :links do
member do
put "like", to: "links#upvote"
put "dislike", to: "links#downvote"
Here we’ve added two routes, one for upvoting and another for downvoting that will update current like and dislikes size in votes table.
Now we need to add upvote route to our root path.
app/views/links/index.html.slim
- @links.each do |link|
= link_to "upvote", like_link_path(link), method: :put
If you click on link, and checkout upvotes size like this in console:
@link = Link.find(1)
@link.get_upvotes.size => 0
You certainly noticed that nothing will happen. Of course because voting only counts when we’re signed in. Try to signin and now click on link. Now if you checkout in console, everything should work.
@link = Link.find(1)
@link.get_upvotes.size => 1
Adding downvoting
Adding downvoting to rails app is reversed process to upvoting, so instead of upvote_by you will add downvote_by
app/controllers/links_controller.rb
def downvote
@link = Link.find(params[:id])
@link.downvote_by current_user
redirect_to links_path
end
Add path to links path.
app/views/links/index.html.slim
= link_to "downvote", dislike_link_path(link), method: :put
Showing link’s score
Next thing we need to is to add link’s score. Adding score is easy, thanks to methods get_upvotes.size and get_downvotes.size we can just add score method to our model.
app/models/link.rb
def score
self.get_upvotes.size - self.get_downvotes.size
And this to your view file
app/views/links/index.html.slim
= link.score
Now if you click on link, you should see that our score is automatically updated by downvotes and upvotes.
That’s all for now, if you don’t understand anything, feel free to ask in discussion.