我目前正在建立一个每周举办自主竞赛的网站。我的逻辑检查前一周是否有指定的获胜者,如果没有,它会滚动,找到胜利者并指定一个奖杯。
逻辑一切正常,但很多都是在应用程序控制器中运行,而在我的核心,我觉得这是不对的。
例如,如果第一名的票数高于第二名,而第二名的票数高于第三名,则需要创建第一名的第二名和第三名奖杯并将其奖励给正确的用户。
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
这是将Trophies直接构建到控制器中,我经常听到'胖模型瘦调控制器'的说法,我觉得我的运行方式与此完全相反!
我如何将奖杯创作转移到模型中?我确信我可以在周模型中使用类似after_save
的东西,但我不完全确定如何保持逻辑运行。我有几次尝试,但我经常收到错误undefined method to_model
。
我知道我可以继续努力让它发挥作用,但我觉得这不是做事的'Rails方式',所以我想在早期阶段解决这个问题。
非常感谢任何帮助。
谢谢!
根据评论进行修改:
感谢您抽出宝贵时间来研究这个问题。在坚果壳中,我想要实现的是一个竞赛从周一到周日的系统。 “活动周”的范围限定为Date.today介于:start_date和:end_date之间的周。
接下来的星期一开始新的一周,这将活跃的一周移动到前一周,然后它将奖杯分配给前一周的前三个条目。它通过检查前一周是否有winner_id来分配奖杯。如果是这样,它不会运行任何逻辑,但是一旦范围移动到新的一周,前几周:winner_id现在为零,所以逻辑运行第一次有人在新的一周来到网站。
愚蠢地说:
因此,用户在当前活动周上的一个条目上投票。一旦一周超出活动范围,它就会为位于本周前3位的用户创建奖杯。
答案 0 :(得分: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
trophy
,其中还有一些user
字段。这不会导致循环依赖吗?或者您是否使用完全相同的条目覆盖现有记录?这需要一些清晰。
答案 1 :(得分: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模型,但不依赖于模型。
我希望这有助于展示如何整理代码。