我很难尝试在我的Ruby on Rails应用程序中实现一个成就系统。
我有很多我想要检查的成就。所有都是由各种控制器中的一些创建动作触发的。
我有一个想法,我将拥有一个成就模型,其中包括控制器和它响应的动作。然后为创建过滤器,检查适用的成就。在实际定义/执行成就时,我会陷入困境。每项成就可能需要不同的数据。例如,人们想要知道用户已经回答了多少问题,另一个问题是他们做出了多少评论,以及第三个用户邀请了多少人回答了问题。
实际上将所有必要的ruby代码直接嵌入到数据库中是最好的做法吗?我可以看到做一个自包含块来执行所有活动记录查找等,并返回true / false,尽管我们仍然存在一些关于事先知道什么是设置的问题(即current_user等)。
任何合理的最佳做法都不会让我感到肮脏?我可以看到一个完整的策略/规则引擎是一条路径,虽然这可能比我计划更多地吓到我。
谢谢! 奥伦
答案 0 :(得分: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
不同的成就是Achievement
模型的所有子类,并使用单表继承,因此它们只存储在一个表中。子类可以包含每个单独成就所需的所有逻辑。您还可以在此模型中存储其他信息,例如获得成就的日期。要确保数据库拒绝重复的成就,您可以在UNIQUE
和type
列上创建user_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
以上只是如何做到这一点的想法,当然可能还有其他人。代码只是一个例子,我还没有真正测试过它。希望这对你有所帮助。
答案 1 :(得分:18)
答案 2 :(得分:7)
我为这项任务写了一个Rails 3 gem,它适用于徽章,积分和排名。您可以在https://github.com/tute/merit中找到源代码。