Mongoid ships with .push on a habtm, which sets a habtm relationship in both directions. Although delete will #delete an associated record, there's no documented way to delete only a relationship that I have seen. Is there a better way of doing this?
Is there a better way of ensuring uniqueness?
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
Following code worked fine for me (mongoid 2.3.x):
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
No inverse_class_name
, no save calls, no special handling, but with exclusion of self-following.
The reason is, that mongoid automatically uses dependent: nullify
if not added to the relation statement. And with autosave: true
the update of relationships get saved (and is only needed for following, because we do not alter followers directly). Without autosave option you need to add a save call in the methods, because mongoid doesn't automatically save relationship updates (since 2.0.0.x).
I put the if-clause as block, so you can alter it with exception handling (else raise FooException
).
The .delete(user)
is okay, also mentioned in the mongoid docs: http://mongoid.org/docs/relations/referenced/n-n.html (scroll down to "DEPENDENT BEHAVIOUR").