挑战标记完成时如何为用户增加积分?模型还是控制器实现?
问题解答
逻辑应该放在模型层
业务逻辑(比如完成挑战后给用户加积分)要封装在模型里,而非控制器。原因如下:
- 符合MVC职责划分:控制器只负责处理请求参数、调用模型方法、返回响应结果,不该掺和具体业务规则。把积分更新逻辑放在模型里,不管是管理员后台标记完成,还是其他场景触发挑战完成,都能自动执行逻辑,避免重复代码。
- 保证数据一致性:模型层的回调能确保只要挑战被标记为完成,积分就会被正确添加,不会因为不同控制器的实现遗漏逻辑。
- 测试更方便:单独测试模型的业务逻辑比测试控制器简单得多,不用模拟HTTP请求。
具体实现方式
根据你给出的关联关系(User -> BattlePass -> Challenge),挑战的完成状态应该存放在中间表battle_pass_challenges里(这是多对多关联的标准中间表)。我们可以在这个中间模型里添加回调,完成积分更新:
# app/models/battle_pass_challenge.rb class BattlePassChallenge < ApplicationRecord belongs_to :battle_pass belongs_to :challenge # 仅当completed字段从false变为true时,执行积分奖励逻辑 after_update :award_points_to_user, if: -> { saved_change_to_completed? && completed? } private def award_points_to_user # 通过关联链定位到对应的用户,精准更新积分 user = battle_pass.user # 使用increment!可以避免并发问题,直接在数据库层面完成数值递增 user.increment!(:points, challenge.points) end end
确保更新正确用户的关键
通过battle_pass_challenge -> battle_pass -> user的关联链,能准确找到拥有该挑战的用户,不会出现张冠李戴的情况。每个battle_pass都属于特定用户,而battle_pass_challenge又绑定了具体的battle_pass和challenge,关联关系天然帮我们锁定了正确的用户对象。
内容的提问来源于stack exchange,提问作者spacerobot
相关产品推荐
相关产品推荐

