2011-12-31 6 views
1

Предположим, у меня есть приложение, которое соответствует двум людям друг против друга, вроде как «горячее» или нет.Как обновить две модели в Rails одновременно?

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

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

+0

Я бы разложил эту информацию в таблицу 'match' и сделал некоторый SQL для вычисления того, что вы хотите. – Reactormonk

ответ

3

Делать это только с помощью People модели ("легкий" способ):

  • Pro: это легко
  • Con: это легко для людей, чтобы раздувать свою "победу" на прессовые параметры формы, используя Firebug или Inspection Хрома инструмент

Если у вас есть эти маршруты:

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 

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


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

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

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

+0

Большое спасибо, очень тщательный и ясный ответ. Быстрый вопрос, хотя у меня есть эти маршруты, которые, как мне кажется, поступают из ресурсов: люди), означает ли это, что отправка формы с помощью метода: method =>: put автоматически использует действие обновления? – Zach

+0

И из любопытства, как бы вы превратили haml выше в erb? Будет ли это form_for с теми же аргументами и скрытым полем? Не совсем уверен, как это должно выглядеть. – Zach

+0

Эй, Зак, извините за поздний ответ. Вы правы в методе ': put'. Если вы посмотрите на список маршрутов, у двух нижних нет имени помощника пути, так что это означает, что они используют имя помощника пути выше (это 'person', а затем вы добавляете' _path' на конец для помощника пути ... если вы хотите использовать URL-адрес, вы должны добавить '_url') – iwasrobbed

0

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

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! 
+0

Что бы я добавил в свои взгляды, чтобы сделать эти параметры доступными в контроллере? – Zach

Смежные вопросы