views:

145

answers:

3

I am new to rails so go easy. I have created a blog with the ability to "vote" on a post by using a feature much like Facebook's "like". I am not using any authentication but would like to restrict voting on a particular post by IP. That is, once someone votes for a post, they cannot vote again (unless they reset their router of course).

I feel like this should be something I affect by modifying the votes or posts Model, but I fear it has to do with Sessions, which...I don't have any experience yet.

Let me know if you need me to post any code. Here is the votes controller.

class VotesController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @vote = @post.votes.create!(params[:vote])

       respond_to do |format|
       format.html { redirect_to @post}
       format.js
     end
  end
end
A: 

You could add an ip_address attribute to your votes table and validates_uniqueness_of :ip_address to ensure that only one vote can come from an IP.

bensie
+6  A: 

Two ways of doing it come to mind right away, there are probably others. Both require storing an IP in the database.

  1. Block the vote from being created with a uniqueness validation.

    class Vote < ActiveRecord::Base
      validates_uniqueness_of :ip_address
      ...
    end
    
  2. Block the vote from being created in the controller

    class VotesConroller < ApplicationController
      ...
      def create
        unless Vote.find_by_post_id_and_ip_address(params[:post_id],request.remote_ip)
           posts.votes.create!(params[:vote].update({:ip_address => request.remote_ip}))
        end
      end
    end
    
EmFi
This is great...how do I pass the ip address to the table from the form. I created the column ip_address.
bgadoci
I tried: <%= f.hidden_field :ip_address => request.remote_ip but didn't work.
bgadoci
You don't even need to collect the ip address in the form. Just have the controller pass it. See the Vote.create line in the 2nd method for how to do that. (Assumes column name is ip_address
EmFi
I have posted my votes controller code above. I am having trouble perhaps because of the collection of post_id.
bgadoci
Adjusted solution to match your code.
EmFi
FYI - the reason you don't want to go the <%= f.hidden_field :ip_address, request.remote_ip %> route is because that's easily modifiable by the user. You need to force it in your controller as EmFi posted above.
bensie
+1  A: 

I would do both EmFi and bensie said and store the IP address with the vote but you might also want to look into creating a blacklist of IPs which you want to block because the represent popular proxy servers (for example, the many proxies in the http://proxy.org/ list).

As you add to the list it will make it at least a little bit harder for users to cheat.

John Munsch
This is great thanks. See my comments on EmFi, need a little help with how to pass to table. I am new.
bgadoci
Good catch, remote_ip is supposed to get the IP behind the proxy using the HTTP\_CLIENT\_IP or HTTP\_X\_FORWARDED\_FOR headers.However, it's probably not flawless.
EmFi