Как обновить две модели в Rails одновременно? - PullRequest
1 голос
/ 31 декабря 2011

Допустим, у меня есть приложение, которое сопоставляет двух людей друг с другом, что-то вроде «горячо или нет».

У меня есть представление соответствия, которое вытаскивает случайных пользователей из базы данных и сопоставляет их друг с другом.Другой.Когда пользователь голосует за одного из людей, я хотел бы увеличить их :wins и :matches_played на 1, но я также хотел бы увеличить проигравших :matches_played на 1, чтобы я мог вычислить рейтинг.

Есть ли способ использовать форму для каждого человека, чтобы выполнить это, или мне нужна промежуточная модель, что-то вроде Match, которая имеет два столбца для победителя и проигравшего, и если да, то как это будет работать.

Ответы [ 2 ]

3 голосов
/ 31 декабря 2011

Выполнение только с использованием модели People («легкий» способ):

  • Pro's: это просто
  • Con: это легко для людейувеличить их "выигрыши", подделав параметры формы с помощью Firebug или Chrome's Inspection tool

Предполагая, что у вас есть следующие маршруты:

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 Версия кода представления:

- # 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:

<%# 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 %>

Затем в вашем контроллере для действия update вы можете выполнить:

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

Как кто-то указал в комментариях, вывероятно, следует обернуть это в так называемую транзакцию , чтобы она постоянно находилась в базе данных, только если все в транзакции успешно сохранено.


Даже при том, что я показываю вам методвыше, я все еще рекомендую использовать модель Match.В конечном счете, использование этой дополнительной модели поможет вам проверить следующие вещи, чтобы люди не могли играть в вашу систему.

  • Пользователь может голосовать только один раз за матч
  • Пользователь не может голосовать заматч с их участием
  • Пользователь не может подделать форму, чтобы раздуть свои выигрыши
  • Разделить опасения в том, что касается моделей, и сделать ваши данные более организованными и понятными для аналитических целей

Да, все это требует больше работы (именно поэтому я не показываю код для него), но это может быть чем-то, что вы хотите сделать, если вас беспокоит что-либо из перечисленного.

0 голосов
/ 31 декабря 2011

Вы должны написать форму отправки, чтобы отправить оба идентификатора пользователя вашему контроллеру с указанием победившего пользователя.Затем вы можете оперировать обоими и сохранить их в БД.

winner = People.find(params[:winner_id])
loser  = People.find(params[:loser_id])
winner.matches_played += 1
winner.wins += 1
loser.matches_played += 1
winner.save!
loser.save!
...