Jan 18 2008

How to limit users to one vote per IP address

Tags: Controllers, Migrations, ModelsKevin @ 9:52 am

A reader Aaron J. writes in response to the short article How to obtain the IP address of the current user:

Do you have any advice on how I can take this a step further? I am looking to limit a given user to one vote per session but I’m not sure how to achieve this. I’d appreciate any help you can offer. Thanks for your time.

Good question, Aaron. Remember that a session is simply tied to your browser cookie, so if we allow one vote per session, all the user has to do is clear their cookies and then vote again. And again. And again! So I think what you mean is how do we allow only one vote per IP address? To enforce that, we'll need to save a list of the IP addresses that have already sent us a vote. And before we record a vote, we need to make sure their IP address isn't already on that list. Further, we should remember which poll number they have voted in so we can have more than one poll in our application. We're going to need a simple table:

# lib/db/migrate/001_voter_log.rb
create_table :vote_log do |t|
  t.column :poll_id, :integer
  t.column :client_ip, :string
end

For simplicity of this example, we'll put all of our logic in the controller. (I won't show the VoteLog model class because it's empty.)


# RAILS_ROOT/app/controllers/poll_controller.rb
def record_a_vote
  poll_id = params[:poll_id]
  client_ip = request.remote_ip

  unless VoteLog.count(:all, :conditions => ['poll_id = ? AND client_ip = ?', poll_id, client_ip]) == 0
    redirect_to :already_voted
  end

  Poll.find(poll_id).record_vote(params[:candidate]) # Or however you count votes
  VoteLog.create(:poll_id => poll_id, :client_ip => client_ip)
end

def already_voted
  render :text => "You already voted, no cheating!"
end

Just keep in mind this approach might not be appropriate in all situations. Due to Network Address Translation (NAT) firewalls, many thousands of people will appear to have the same client_ip. This is particularly true in corporate environments. If that's a concern, you'll need to go with a full-blown registered-user approach.

Further Reading

How to obtain the IP address of the current user

Feedback and Article Ideas

Want to see a topic explored here? Send Me a Message.


Nov 30 2007

Ruby, Rails and hash’s with_indifferent_access

Tags: RubyKevin @ 5:31 pm

Long Names

Ruby developers like to be clear in their naming of variables, modules, classes, methods, and so on. I believe this comes from the idea that code should need very few inline comments if it is written clearly and descriptively. This descriptive naming strategy, combined with the decidedly non-English origins of Ruby (Japanese) and Rails (Danish), often result in oddly-named creations such as #execute_query_as_logged_in_user_without_transaction_logging (which I just made up), and #validates_numericality_of (which is real).

A newcomer might find these tongue-twisting, hyper-descriptive naming conventions maddening, but most of the time the intent becomes so much clearer as a result, it becomes infectious; in no time you find yourself writing your own 30-letter, borderline-semantically-correct method names and producing highly maintainable, readable, self-documenting code. That doesn't mean it happens all the time, though...

Continue reading "Ruby, Rails and hash’s with_indifferent_access"


Sep 04 2007

Indispensable Rails Plugins

Tags: Plugins, acts_as_solr, attachment_fu, geokit, paginating_findKevin @ 10:38 am

Obie Fernandez's post about his most favored plugins prompted me to consider how much I use not only the Rails core framework, but also some excellent plugins that let me focus more on solving domain problems rather than technical ones. Below, the plugins I find indispensable in my work on Dibs.net.

Continue reading "Indispensable Rails Plugins"


Aug 30 2007

Restoring Rails session data when cookies aren’t available

Tags: Controllers, FiltersKevin @ 8:04 pm

C is for Cookie

If you've ever needed to implement user-friendly upload, you know intimately what a pain it is to get right. The web just isn't built for uploading files from a browser. I mean, it kinda works, but even then only with a dozen or so limitations. Even the major photo and video sites have tried various solutions to make this easier for users. So when I built Dibs.net, I decided rather quickly to abandon all hope of getting it working flawlessly with plain ol' Javascript and HTML, and instead looked into using a fairly nonintrusive Flash uploader component. (Without Flash installed, it just falls back to a simple HTML-based file-upload form.)

That's not to say it was perfectly simple to get working with Rails. Because Dibs.net accepts uploads only from logged-in users, I ran into two limitations that would not allow me to use this solution:

  • Flash doesn't send the cookies from the browser (at least it doesn't in Firefox; it might in IE)
  • Rails doesn't support non-cookie sessions

Because Flash doesn't send the session cookie, Rails thinks the request is coming from a new, logged-out user and creates a new session for it. Adding a cookies feature to Flash was well out of my hands since I don't work for Adobe, so I looked into a way to restore the session from a session key passed as a URL parameter. After some experimentation, I found a solution that works great.

Continue reading "Restoring Rails session data when cookies aren’t available"


Aug 27 2007

De-tangling attr_reader, attr_writer and attr_accessor from attr_protected & attr_accessible (Part 1)

Tags: Models, RubyKevin @ 6:00 pm

Car crash

What a mess. You have undoubtedly run across these methods sprinkled throughout the Ruby and Rails world. If you've been working with Rails for even a short time, you've probably read a little about security and attr_accessible. But do you really understand what each of them do and when to use them?
I'm not a fan of whoever made these methods so closely named, especially because they serve very different purposes: two are specific to Rails (or more accurately, ActiveRecord), while the other three are Ruby core methods. When I have a need for any of them, I still have to really think about which one I actually want to use. Often I still have to glance at the rdocs to be reassured my choice is the right one. So let's dive in and figure out what the heck these are supposed to do, and when to use them.

Continue reading "De-tangling attr_reader, attr_writer and attr_accessor from attr_protected & attr_accessible (Part 1)"


Aug 26 2007

How to obtain the IP address of the current user

Tags: ControllersKevin @ 10:56 pm

Some house address

Web applications can receive requests directly, via a CGI process, through proxy servers, relayed from front-end web servers, and so on. This can complicate how you might find out where the request originated if you, for example, wanted to limit an online poll to one vote per IP address. Luckily, Rails consolidates most of the ways to get this info into a single convenience method on the request object for us.

Continue reading "How to obtain the IP address of the current user"