0

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

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

Например, если на первом месте больше голосов, чем на втором месте, а на втором месте больше голосов, чем на третьем месте, ему нужно будет создать трофей первого и третьего места и вознаградить его за правильных пользователей.

 if first_place > second_place && second_place > third_place 
      @week_previous.winner_id = week_entries[0].id 
      @week_previous.save 

      first_trophy = week_entries[0].user.trophies.new 
      first_trophy.week_id = @week_previous.id 
      first_trophy.user_id = week_entries[0].user_id 
      first_trophy.position = "first" 
      first_trophy.country = week_entries[0].user.country 
      first_trophy.pro  = false 
      first_trophy.save 

      if second_place >= 1 
      second_trophy = week_entries[1].user.trophies.new 
      second_trophy.week_id = @week_previous.id 
      second_trophy.user_id = week_entries[1].user_id 
      second_trophy.position = "second" 
      second_trophy.country = week_entries[1].user.country 
      second_trophy.pro  = false 
      second_trophy.save 
      end 

      if third_place >= 1 
      third_trophy = week_entries[2].user.trophies.new 
      third_trophy.week_id = @week_previous.id 
      third_trophy.user_id = week_entries[2].user_id 
      third_trophy.position = "third" 
      third_trophy.country = week_entries[2].user.country 
      third_trophy.pro  = false 
      third_trophy.save 
      end 
     end 

Это строит соревнования прямо в контроллер, и я часто слышал «жира модели тощий контроллер» аргумент, и я чувствую, как я бегу это идет полностью против этого!

Как перенести творения трофеев в модель? Я уверен, что я мог бы использовать что-то вроде after_save в модели недель, но я не совсем уверен, как сохранить работу логики. У меня было несколько попыток, но я часто получаю ошибку undefined method to_model.

Я знаю, что я мог бы просто пахать и заставить его работать, но я просто чувствую, что это не «Rails Way», чтобы делать что-то, поэтому я хотел бы разобраться на ранних этапах.

Любая помощь очень ценится.

Спасибо!

Редактировать на основе комментариев:

Спасибо, что нашли время, чтобы посмотреть на это. В ореховой раковине я пытаюсь добиться того, чтобы система проходила с понедельника по воскресенье. «Активная неделя» привязана к Неделе, где Date.today находится между: start_date и: end_date.

В следующий понедельник начинается новая неделя, это перемещает то, что было активной неделей на предыдущую неделю, и затем выделяет трофеи в верхние 3 записи за предыдущую неделю. Он выделяет трофеи, проверяя, имела ли предыдущая неделя значение winner_id. Если это так, он не запускает какую-либо логику, но после того, как область движется на новую неделю, предыдущие недели: winner_id теперь нуль, поэтому логика запускается в первый раз, когда кто-то приходит на сайт в новую неделю.

немой вниз:

  • Неделя является ресурсом, который записи has_many.
  • Запись принадлежит _ пользователю, принадлежит_не недели и has_many Голоса.
  • вотума belongs_to въездного
  • Пользователь, has_many Запись и has_many Трофеи
  • трофей принадлежит Пользователю и belongs_to Недели

Таким образом, пользователям голосовать на записи в текущей активной неделе. Как только неделя выходит за пределы активной области, она создает Trophies для Пользователей, которые помещаются в верхние 3 позиции недели.

+0

Вы правы, что это должно быть в модели. Похоже, что его нужно немного подобрать. Можете ли вы добавить дополнительную информацию о своей схеме и о том, что вы пытаетесь сделать? –

+0

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

+0

Это вопрос, который больше по теме на http://codereview.stackexchange.com –

ответ

1

Трудно дать с хорошим советом, не зная контекста.Но то, что бросается в глаза, заключается в том, что в этом коде много повторений и что вы обновляете трофеи пользователей в этих повторениях. Поэтому я бы, по крайней мере переместить эту логику в пользователя в качестве первого шага:

# in user.rb 
def record_trophy_win(prev_week, entry, position) 
    trophies.create(
    week_id: prev_week.id, 
    user_id: entry.user_id, 
    position: position, 
    country: entry.user.county, 
    pro:  false 
) 
end 

Это позволяет изменять парциальное в контроллере к этому:

if first_place > second_place && second_place > third_place 
    @week_previous.update_attribute(:winner_id, week_entries[0].id) 

    first_trophy = week_entries[0].user.record_trophy_win(
    @week_previous, week_entries[0], 'first' 
) 

    second_trophy = week_entries[1].user.record_trophy_win(
    @week_previous, week_entries[1], 'second' 
) if second_place >= 1 

    third_trophy = week_entries[2].user.record_trophy_win(
    @week_previous, week_entries[2], 'third' 
) if third_place >= 1 
end 

Эта логика может на следующей стадии принадлежат в класс Trophy. Зависит от контекста ...

И я заметил, что у вашего week_entry есть user. И вы добавляете к этому user a trophy, который снова имеет некоторые поля user. Не приводит ли к циклической зависимости? Или вы переопределяете существующую запись с помощью тех же самых записей? Это требует некоторой ясности.

+0

Это, безусловно, шаг вперед для меня! Это те процессы, которые я искал. Я знал, что могу передать его в модель, я просто не был уверен, как передать ее. Извините за отсутствие контекста в исходном ответе, я включил ссылку на репо, где вы можете увидеть мой ужасный код во всей своей славе. Lol – abbott567

+0

Я отметил это как правильный ответ, так как я спросил, как переместить некоторые из них в модель, и это именно то, что это делает. У меня все еще есть много рефакторинга, но для меня это стало намного понятнее. благодаря – abbott567

1

Одним из способов изолировать бизнес-логику является шаблон проектирования служебного объекта. Пример:

class TrophyRewarder 
    def initialize(winners, last_week_winners) 
    @winners = winners 
    @last_week_winners = last_week_winners 
    end 

    def reward(options) 
    # All code to determine and store winners comes here 
    end 
end 

Вы можете поместить этот код в папку app/services и вызвать его в контроллер, как это:

trophy_rewarder = TrophyRewarder.new(users, Winners.from_last_week) 
trophy_rewarder.reward(options) 

Хорошая вещь, что вы можете назвать этот объект службы от контроллера, но и из фоновой задачи. Другое дело, что объект службы может использовать множество разных моделей данных/AR, но не привязан к модели.

Надеюсь, это поможет немного показать, как вы можете организовать свой код.

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