如何在RoR中实现成就系统

tei*_*ich 40 ruby-on-rails

我很难尝试在我的Ruby on Rails应用程序中实现一个成就系统.

我有很多我想要检查的成就.所有都是由各种控制器中的一些创建动作触发的.

我有一个想法,我将有一个成就模型,其中包括控制器和它响应的动作.然后为创建过滤器,检查适用的成就.在实际定义/执行成就时,我会陷入困境.每项成就可能需要不同的数据.例如,人们想要知道用户已经回答了多少问题,另一个问题是他们做出了多少评论,以及第三个用户邀请了多少人回答了问题.

实际上只需将所有必要的ruby代码直接嵌入到DB中,这是最好的做法吗?我可以看到做一个自包含块来执行所有活动记录查找等,并返回true/false,尽管我们仍然存在一些关于事先知道什么是设置的问题(即current_user等).

任何合理的最佳做法都不会让我感到肮脏?我可以看到一个完整的策略/规则引擎是一条路径,虽然这可能会吓到我而不是计划一个.

谢谢!奥伦

mol*_*olf 52

我同意你使用Achievement模型的想法.

但是,您可能不应该在控制器中实现触发器.想象一下,你有两种发表评论的方式; 你将不可避免地得到代码重复.这种行为属于模型.

假设您要跟踪用户发表的评论数量,并为100条评论奖励成就.您可以拥有以下型号:

class User < ActiveRecord::Base
  has_many :comments
  has_many :achievements

  def award(achievement)
    achievements << achievement.new
  end

  def awarded?(achievement)
    achievements.count(:conditions => { :type => achievement }) > 0
  end
end

class Achievement < ActiveRecord::Base
  belongs_to :user
end

class Comment < ActiveRecord::Base
  belongs_to :user
end

class CommentAchievement < Achievement
  def self.check_conditions_for(user)
    # Check if achievement is already awarded before doing possibly expensive
    # operations to see if the achievement conditions are met.
    if !user.awarded?(self) and user.comments.size > 100
      user.award(self)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

不同的成就都是Achievement模型的子类,并使用单表继承,因此它们只存储在一个表中.子类可以包含每个单独成就所需的所有逻辑.您还可以在此模型中存储其他信息,例如获得成就的日期.要确保数据库拒绝重复的成就,您可以UNIQUEtypeuser_id列上创建索引.

CommentAchievement.check_conditions_for(user)可以随时调用.您可以创建一个不时运行的后台作业,或者您可以创建一个观察者:

# app/models/comment_achievement_observer.rb
class CommentAchievementObserver < ActiveRecord::Observer
  observe :comment

  def after_create(comment)
    CommentAchievement.check_conditions_for(comment.user)
  end
end

# config/environment.rb
config.active_record.observers = :comment_achievement_observer
Run Code Online (Sandbox Code Playgroud)

以上只是如何做到这一点的想法,当然可能还有其他的.代码只是一个例子,我还没有真正测试过它.希望这对你有所帮助.


小智 18

非常好的解决方案,molf.

我将它转换为插件/ gem,带有生成器以获得新的成就:

http://github.com/paulca/paths_of_glory

快乐实现!


Tut*_*teC 7

我为这项任务写了一个Rails 3 gem,它适用于徽章,积分和排名.您可以在https://github.com/tute/merit中找到源代码.