Let's say I have an app that matches two People against each other, kind of like "hot or not."
I have my matchup view pulling random users out of the database and matching them up against each other. When a user votes for one of the people I would like to increase their :wins
and :matches_played
by 1 but I would also like to increase the losers :matches_played
by 1 so that I can calculate rankings.
Is there is a way to use a form for each person to accomplish this or do I need a model in between, something like Match that has two columns for the winner and loser, and if so how would this work.
Doing it only using a People model (the "easy" way):
Assuming you have these routes:
new_person GET /people/new(.:format) {:action=>"new", :controller=>"people"}
edit_person GET /people/:id/edit(.:format) {:action=>"edit", :controller=>"people"}
person GET /people/:id(.:format) {:action=>"show", :controller=>"people"}
PUT /people/:id(.:format) {:action=>"update", :controller=>"people"}
DELETE /people/:id(.:format) {:action=>"destroy", :controller=>"people"}
HAML Version of the view code:
- # Person A form
= form_tag(person_path(@personA, :loser_id => @personB), :method => :put) do
= submit_tag "Vote for Person A"
- # Person B form
= form_tag(person_path(@personB, :loser_id => @personA), :method => :put) do
= submit_tag "Vote for Person B"
ERB Version:
<%# Person A form %>
<% form_tag(person_path(@personA, :loser_id => @personB), :method => :put) do %>
<%= submit_tag "Vote for Person A" %>
<% end %>
<%# Person B form %>
<% form_tag(person_path(@personB, :loser_id => @personA), :method => :put) do %>
<%= submit_tag "Vote for Person B" %>
<% end %>
Then in your controller for the update
action you could do:
def update
People.transaction do
winner = People.find(params[:id])
loser = People.find(params[:loser_id])
# Increment the winner
winner.increment! :matches_played
winner.increment! :wins
# Increment the loser
loser.increment! :matches_played
end
respond_to do |format|
format.html { redirect_to new_match_path }
end
end
As someone pointed out in the comments, you should probably wrap this in what is called a transaction so that it's only permanently in the database if everything within the transaction saves successfully.
Even though I'm showing you the method above, I'd still recommend using a Match
model. Ultimately, using that extra model will help you validate the following things so people can't game your system.
Yes, this all requires more work (which is why I'm not showing code for it), but it may be something you want to do if you're concerned about any of the above.