2

I have a Ruby on Rails 3.2 application where users are able to upload videos directly to youtube with the Youtube_it Rails gem. After the video is uploaded, the people are able to vote on the videos. I have it setup now where anyone can vote on the videos and they don't have to register(using devise) to vote on the videos.

I would like to limit the votes to 1 vote per day per IP address. If a person has voted from an IP address, they should not be able to vote again for 24 hours.

I'm new to rails and I can't seem to figure out how to implement this. I think I would have to create a model to store the users IP address in it with request.remote_ip. How would I limit their voting to once per day?

My routes.rb

resources :videos do
 collection do
  put '/vote_up/:id' => "videos#vote_up", :as => :vote_up
 end
 new do
  post :upload
  get  :save_video
 end
end

My videos show view

 <%= link_to vote_up_videos_url(@video.id), class: "btn btn-main", :method => :put do %>
   <i class="fa fa-thumbs-up"></i> Upvote this video
 <% end %>

Videos controller

def vote_up
 @video = Video.find(params[:id])
 @video.update_attribute(:votes_up, (@video.votes_up.to_i + 1))
 redirect_to @video
end
stiweb2003
  • 73
  • 3
  • 6
  • What do you do if there is more than one user at an IP address? Two people at one address, perhaps, or a carrier using carrier-grade NAT could have thousands of users using one IP address. –  May 20 '14 at 01:48
  • Should the user be not be able to vote again on the same video or on any video? Can only registered users vote? – spickermann May 20 '14 at 01:48
  • You don't want to do this. You have no control over and no way of knowing where along the chain the request IP address is coming from. Increasingly, given the lack of IPv4 addresses, ISPs are forced to implement NAT on their end, meaning that one IP address you see could easily be mapped to hundreds of individual people. The same is true of organizations (libraries, wifi spots, universities) and cell connections. – lc. May 20 '14 at 01:50
  • @MikeW if there is more than one user at an IP address, they will have to vote the next day. – stiweb2003 May 20 '14 at 01:53
  • @spickermann the voter should no be able to vote again on the same video, but they can vote on other videos. Also, you don't have to be registered to vote, only to submit videos. – stiweb2003 May 20 '14 at 01:55
  • @lc. point taken. Do you have another way of limiting votes per day? – stiweb2003 May 20 '14 at 01:59
  • The only thing I can really think of is the cookie approach. But it won't stop people from voting once with each browser/device combination. You could do once per email but that won't stop people from voting with multiple emails. And you could force people to register but that also won't stop people from making multiple users each with a different associated email address. And you could force people to make a telephone call to you to vote but they could call once from home, once from the payphone outside, once from their cell, once more from their daughter's cell, and finally again from work. – lc. May 20 '14 at 02:05
  • Sorry to give a non-answer but are you trying to just make things "easy" for the normal user, block people from intentionally voting twice, or prevent spammers? You will then have to balance the problem you are trying to solve with the possible solutions and workarounds. Remember where there's a will (and money to be made), there's definitely a way. If it's just for the normal user and you're not using this to prevent spam votes, I would just store a cookie and be done with it. – lc. May 20 '14 at 02:09
  • Many years ago I was asked by a relative who wanted to vote multiple times on such a site for advice on how to acquire a new IP address. It took me about 5 minutes to figure out simply resetting his DSL modem would provide a new IP address and a fresh ballot. Needless to say, his favorite option won thanks do his many votes. –  May 20 '14 at 05:30

1 Answers1

1
# in controller
def vote_up
 video = Video.find(params[:id])
 video.vote!(request.ip)

 redirect_to video
end

# in video model
def vote!(ip)
  unless Vote.recent.exists?(:ip => ip, :video_id => id)
    increment!(:votes_up) 
    Vote.create(:ip => ip, :video_id => id)
  end
end

# in vote model
class Vote < ActiveRecord::Base
  scope :recent, -> { where("created_at > ?", 24.hours.ago) }
end

# migration
class CreateVotes < ActiveRecord::Migration
  def change
    create_table :votes do |t|
      t.integer :video_id
      t.string  :ip
    end
    add_index :votes, :video_id, :ip
  end
end
spickermann
  • 100,941
  • 9
  • 101
  • 131