DEV Community

James Chou
James Chou

Posted on

Vote on Rails[Bonus: Vote as a guest!]

As a fellow Rails developer, you have most likely received the task of creating something similar to a blogging app (bare with me if you haven't). Recently, I have had to create one complete with commenting, sharing, and voting capabilities. Typically I would take time to map out the schema prior to running rails new but in this case I was pressed for time. Luckily I had the act_as_voteable gem to save the day!

Installation is very basic as all you need to do is include the gem in your gemfile and bundle:

gem 'acts_as_votable', '~> 0.11.1'

and generate + migrate their migration:

rails generate acts_as_votable:migration
rake db:migrate

Now let's roll!

My favorite thing about this gem is that the methods to create votes and show votes are simple. First thing we need to do is make the associations between the objects you want to vote on and the voters. In this case, I want to users to vote on my posts. Here is a look at my User.rb and Post.rb files:

user.rb

  # Voter.
  acts_as_voter

post.rb

  #Votee
  act_as_votable

Now that the app knows that users vote on posts, we need to create upvote and downvote methods in our Post controller. The awesome thing is that the gem already limits one vote per user(default but can allow duplicates) and you can also make vote weighted based on user role if you wanted! I did not use weighted votes in my app but if you want learn more about how else you can play around with voting, definitely look at the great documentation that ryanto has for his gem!

Post Controller

def upvote
    @post = Post.find(params[:id])
    @post.liked_by current_user
    #can change current_user to any other voter
end

def downvote
    @post = Post.find(params[:id])
    @post.disliked_by current_user
    #can change current_user to any other voter
end

and in my html view:

<%= link_to "Like", like_post_path(@post, method: :put) %>

What you have read so far is a barebones quick install tutorial and there is definitely potential for further manipulation of votes. See Documentation!. But I did find myself in an issue...what if I want guests to vote?!

Through extensive research from various sources(google,stackoverflow,my sensai, etc) I found a way to do this with session ids!

This time, we have to allow users AND sessions to act as voters; we need to add act_as_voter in both of the votersession.rb and user.rb files. But first we need to generate a votersession model.

rails g migration votersessions session_id:string
rails db:migrate

and now we simple need to change our controller to use the User object to vote and, if not available, the session id instead. Here's my moist(not DRY)

  def upvote
    @idea = Idea.find(params[:id])
    # vote as user if logged in
    if current_user
      @idea.upvote_by current_user
    # else vote is associate with session
    else
      @session = VoterSession.find_by(session_id: request.session_options[:id])
    # Create new votersession if unique id does not exist
        if @session == nil
          @session = VoterSession.create(session_id: request.session_options[:id])
        end
      @idea.upvote_by @session
    end

Keep in mind, there is still a chance for voters to vote more than once, for example, if the user is not logged in, they can vote again each time they clear their cookies or use a different computer so I recommend this method for smaller apps that need a quick voting structure.

My hope is that this post can be of use to a dev out there or at the very least sparked an idea. Drop a line if you have any questions!

Top comments (2)

Collapse
 
andy profile image
Andy Zhao (he/him) • Edited

Nice, we use the acts_as_follower gem for our following system here. 😁

Also, you can use triple back ticks for code blocks to make things easier to read:

def method
  #do something
end
Collapse
 
ben profile image
Ben Halpern

Looks nice. So many of the acts_as gems in Rails are wonderful.