Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Ruby

How to implement a voting system in Rails?

Hi. I am a beginner and I am building an app in rails , and at the moment I have user, post, and comment models. I want to implement a voting system for posts and comments. I have searched online but most of the tutorials are either using gems or they only have an upvote system( I have found one which has downvote as well, but I find it complicated and can't understand what they are doing). So can anybody show me how to do it, or send me a link to a tutorial that is for beginners?! Thank you!

1 Answer

First try stablishing the relation between the post, the user and the vote. for example i would do something like this at first:

rails generate model Vote user:references post:references

Then at the models I would set the relation:

def Vote < ApplicationRecord
   belongs_to :user
   belongs_to :post
end

def Post < ApplicationRecord
   has_many :votes
   has_many :votants, through: :votes
end

def User < ApplicationRecord
  has_many :votes
  has_many :liked_posts, through: :votes
end

having this relation will add a method called "liked_posts" to your users, which will return the posts that the user has voted for, then a "votants" method to your Post Model which will return the users that have voted for that single post.

Then you should have some sort of machanism to make a user vote for a post you can approach this in a number of ways, right now i would go with the simplest solution i think of right now:

class VotesController < ApplicationController
...
  def create
    vote = Vote.new(vote_params)
    if vote.save
      #do something
    else 
      # flash that something went wrong
    end
  end
...
  private

  def vote_params
     params.require(:vote).permit(:user_id, :post_id)
  end
end

Ok, so now you got a simple voting system, if you would like to add an upvote and downvote you should probably modify your Vote table doing something like this:

rails generate migration AddVoteTypeToVotes vote_type:integer

We'll be using an Enum type to achieve this, so going back to the votes model:

class Votes < ApplicationRecord
...
  enum selectable_vote_types: [ :upvote, :downvote ]

end

so with this changes we should be able to send 0 if the vote it's an upvote and 1 if the vote it's a downvote to our controller, so we should change the strong params inside our controller:

class VotesController < ApplicationController
...
  private

  def vote_params
    params.require(:vote).permit(:user_id, :post_id, :vote_type)
  end
end

there's one more challenge we should be facing by now, we are sending the user_id to the controller, but that's not quiet practical, so, if you are using devise for authentication you could just take the user_id from the current_user, if you are not using devise probably you should be sending the user_id through the request, or create your own current_user method.

This same thing can be implmented to the comment Model

But anyway i hope this helps.