在一个简单的mongoid数据模型上,用户有很多评论,我想在用户写至少一条评论时给用户一个特定的徽章.所以我建立了一个像这样的观察者:
class CommentBadgeObserver < Mongoid::Observer observe :comment def after_create(comment) CommentBadge.check_conditions_for(comment.user) end end class CommentBadge < Badge def self.check_conditions_for(user) if user.comments.size > 1 badge = CommentBadge.create(:title => "Comment badge") user.award(badge) end end end
user.award方法:
def award(badge) self.badges << badge self.save end
以下测试失败(但我想这是正常的,因为观察者在后台执行?)
it 'should award the user with comment badge' do @comment = Factory(:comment,:user => @user) @user.badges.count.should == 1 @user.badges[0].title.should == "Comment badge" end
什么是验证此行为的最佳方法?
解决方法
我有一个独立的代码改编(见下文).我不得不做三个小改动,让它按照你期望的方式工作.
要使Observer正常工作,您必须实例化它.在我的例子中,我需要添加以下行:
Mongoid.observers = CommentBadgeObserver Mongoid.instantiate_observers
在Rails中你可以实现相同的功能,将它添加到config / application.rb(根据docs):
config.mongoid.observers = :comment_badge_observer
我认为CommentBadge.check_conditions_for中还存在一个小的逻辑错误,> 1应该> 0.
最后,我更改了User#award方法以保存徽章而不是用户,因为存储关系的“外键”字段位于徽章一侧.
class Comment include Mongoid::Document field :name belongs_to :user end class CommentBadgeObserver < Mongoid::Observer observe :comment def after_create(comment) CommentBadge.check_conditions_for(comment.user) end end class Badge include Mongoid::Document field :title belongs_to :user end class CommentBadge < Badge def self.check_conditions_for(user) if user.comments.size > 0 badge = CommentBadge.create!(:title => "Comment badge") user.award(badge) end end end class User include Mongoid::Document field :first_name has_many :comments has_many :badges def award(badge) self.badges << badge badge.save! end end Factory.define(:user) do |u| u.first_name 'Bob' end Factory.define(:comment) do |c| c.name 'Some comment...' end # Observers need to be instantiated Mongoid.observers = CommentBadgeObserver Mongoid.instantiate_observers describe CommentBadgeObserver do it 'should create badges' do @user = Factory.build(:user) @comment = Factory(:comment,:user => @user) @user.badges.count.should == 1 @user.badges[0].title.should == "Comment badge" end end