2011-11-22 18 views
8

En un modelo de datos mongoide simple con un usuario que tiene muchos comentarios, quiero otorgar al usuario una insignia específica cuando escribe al menos 1 comentario. Así que he creado un observador de esta manera:Cómo probar Mongoid :: Observer con rspec

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 

El método user.award: (¿pero supongo que es normal porque los observadores se ejecutan en segundo plano)

def award(badge) 
    self.badges << badge 
    self.save 
end 

no pasa la prueba siguiente

¿Cuál es la mejor manera de validar este comportamiento?

Respuesta

7

Tengo una adaptación de trabajo autónoma de su código (ver a continuación). Tuve que hacer tres pequeños cambios para que funcione de la manera que esperabas.

Para que el Observer funcione en todo lo que tiene que crear una instancia. En mi ejemplo, yo tenía que añadir las líneas:

Mongoid.observers = CommentBadgeObserver 
Mongoid.instantiate_observers 

en rieles que puede lograr lo mismo que añadir esto a config/application.rb (según la docs):

config.mongoid.observers = :comment_badge_observer 

creo que hay también es un pequeño error de lógica en CommentBadge.check_conditions_for, el > 1 debe ser > 0.

Finalmente cambié el método User#award para guardar la insignia en lugar del usuario, porque el campo 'clave externa' que almacena la relación está en el lado de la credencial.

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 
+0

Funciona muy bien! Muchas gracias Steve! – obo

+0

Eso es bueno saber y gracias. ¿Lo conseguiste trabajando en tus Rails y fue la instanciación del observador u otra cosa? – Steve

+0

Sí, lo hice trabajando en mi aplicación; Tuve que establecer las dos líneas de la instanciación del observador en mi archivo de especificaciones. – obo

Cuestiones relacionadas