2011-12-20 22 views
5

Mongoid se envía con .push en un habtm, que establece una relación habtm en ambas direcciones. Aunque delete #recuperá un registro asociado, no hay forma documentada de eliminar solo una relación que he visto. ¿Hay una mejor manera de hacer esto?HABTM mongoid following/follower

¿Existe alguna forma mejor de garantizar la singularidad?

has_and_belongs_to_many :following, {class_name: 'User', inverse_of: :followers, inverse_class_name: 'User'} 
    has_and_belongs_to_many :followers, {class_name: 'User', inverse_of: :following, inverse_class_name: 'User'} 

    def follow!(user) 
    self.following.push(user) # this pushes the inverse as well 
    self.following_ids.uniq! 
    self.save! 
    user.follower_ids.uniq! 
    user.save! 
    end 

    def unfollow!(user) 
    self.following.delete(user.id) 
    self.save! 
    user.followers.delete(self.id) 
    user.save! 
    end 

Respuesta

18

siguiente código funcionó bien para mí (2.3.x MongoId):

class User 
    include Mongoid::Document 

    field :name, type: String 

    has_and_belongs_to_many :following, class_name: 'User', inverse_of: :followers, autosave: true 
    has_and_belongs_to_many :followers, class_name: 'User', inverse_of: :following 

    def follow!(user) 
    if self.id != user.id && !self.following.include?(user) 
     self.following << user 
    end 
    end 

    def unfollow!(user) 
    self.following.delete(user) 
    end 
end 

Sin inverse_class_name, sin salvación llamadas, manejo especial, pero con exclusión de auto-siguiente.

La razón es que mongoid automáticamente usa dependent: nullify si no se agrega a la declaración de relación. Y con autosave: true se guarda la actualización de las relaciones (y solo se necesita para seguir, porque no alteramos los seguidores directamente). Sin la opción de autoguardar, debe agregar una llamada a guardar en los métodos, porque mongoid no guarda automáticamente las actualizaciones de relación (desde 2.0.0.x).

Puse la cláusula if como bloque, por lo que puede modificarla con manejo de excepción (else raise FooException).

.delete(user) está bien, también se menciona en los documentos mongoid: http://mongoid.org/docs/relations/referenced/n-n.html (desplácese hacia abajo a "COMPORTAMIENTO DEPENDIENTE").

+0

Algunas cosas buenas aquí. Sin embargo, hice algunas pruebas antes, y caí en la misma trampa (a menos que esté equivocado): .delete (usuario) borra al usuario de la base de datos, y anula se refiere a cualquier referencia hecha al usuario ahora eliminado –

+0

.delete está en el hash .following no en el objeto del usuario en sí. Al igual que doc, dice "Huérfano, una relación infantil única". Hace el trabajo, lo probé y funciona. – asaaki

+0

El código '! Self.following.include? (User)' es genial cuando no tienes demasiados usuarios dentro de la siguiente relación, pero si tienes como 10K usuarios ... El rendimiento no es muy bueno:/ –