Skip to content
BoogeyCodesPublic

About

A small polls API built with Ruby on Rails (API-only): create polls, vote once per voter, live results with percentages

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

quickpoll

CI Ruby on Rails 7.1 Ruby 3.1+ License: MIT

A small polls API built with Ruby on Rails (API-only). Create a poll with options, let people vote once each, and read back live results with vote counts and percentages.

# create a poll
curl -X POST localhost:3000/polls \
  -H 'Content-Type: application/json' \
  -d '{"question":"Tabs or spaces?","options":["Tabs","Spaces"]}'

# vote (one vote per voter token per poll)
curl -X POST localhost:3000/polls/1/votes \
  -H 'Content-Type: application/json' \
  -d '{"option_id":1,"voter_token":"anon-abc"}'

# {"id":1,"question":"Tabs or spaces?","closed":false,"total_votes":1,
#  "options":[{"id":1,"label":"Tabs","votes":1,"percentage":100.0},
#             {"id":2,"label":"Spaces","votes":0,"percentage":0.0}]}

Why

A polls API is a small domain with a surprisingly complete validation story, which makes it a good, honest demonstration of a Rails backend: associations between polls, options and votes; validations that enforce real rules ("one vote per voter", "an option must belong to the poll", "no voting on a closed poll"); a uniqueness constraint backed at both the model and database level; and a clean JSON error contract. It is deliberately compact so the Rails idioms are the subject.

API

GET    /polls              list polls, newest first
POST   /polls              create a poll { question, options: [..] }  (needs >= 2 options)
GET    /polls/:id          a poll with results (counts and percentages)
POST   /polls/:id/close    close a poll to further voting
POST   /polls/:id/votes    cast a vote { option_id, voter_token }
GET    /up                 health check

Responses are JSON. Validation failures return 422 with an errors array; unknown records return 404. For example, a second vote from the same voter_token returns:

{ "errors": ["Voter token has already voted in this poll"] }

Data model

Poll (question, closed)
  has_many :options
  has_many :votes

Option (poll_id, label)
  belongs_to :poll
  has_many :votes

Vote (poll_id, option_id, voter_token)
  belongs_to :poll
  belongs_to :option
  # unique on (poll_id, voter_token), in the model and as a DB index

Keeping poll_id on the vote (alongside option_id) is what lets "one vote per voter per poll" be a simple scoped uniqueness rule, enforced both by an ActiveRecord validation and a unique database index so a race cannot slip a duplicate through.

Rules enforced

  • A poll needs a question and at least two options.
  • A voter (identified by an opaque voter_token) may vote once per poll, but the same token can vote in other polls.
  • A vote's option must belong to the poll it is cast in.
  • No votes once a poll is closed.

Each of these is covered by a test.

Running locally

bundle install
bin/rails db:prepare
bin/rails server            # http://localhost:3000

Testing

bin/rails db:prepare
bin/rails test

Twenty-two tests with Rails' built-in Minitest: model tests for the vote rules and the results calculation, and request tests that drive the JSON API end to end, asserting status codes, the error contract and the computed percentages. CI runs the suite against a fresh SQLite database on every push.

Project layout

app/models        Poll, Option, Vote (associations and validations)
app/controllers   PollsController, VotesController, ApplicationController (JSON error handling)
config/routes.rb  nested RESTful routes
db/migrate        the three tables and the unique vote index
test/             model and request tests

Notes

This repository was written as an API-only Rails app; db/schema.rb is generated by db:migrate rather than committed, so CI migrates a fresh database for each run.

Ideas for later

  • Poll expiry (auto-close after a deadline).
  • Rate limiting and abuse protection on voting.
  • A results endpoint that streams live updates over Action Cable.

License

MIT

About

A small polls API built with Ruby on Rails (API-only): create polls, vote once per voter, live results with percentages

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages