I'm trying to create an event platform using MongoDB as the db. I want a many-to-many relationship between Events
and Users
. The thing is, I want there to be properties in the relationship (e.g., Users
can either be confirmed or unconfirmed for a specific Event
). I realize this would be ideally suited for an RDBMS, but I'm using MongoDB for reasons that I'm taking advantage elsewhere and I would prefer to continue using it.
What I would like is for each Event
to embed many Guests
, which belong to Users
. That way, I can see which users are attending an event quickly and with only one query. However, I would also like to see which Events
a User
is attending quickly, so I would like each User
to have an array of Event
ids.
Here is a code summary.
# user of the application
class User
has_many :events
end
# event that users can choose to attend
class Event
embeds_many :guests
has_many :users, :through => :guests # Won't work
end
# guests for an event
class Guest
field :confirmed?, type: Boolean
embedded_in :event
belongs_to :user
end
# Ideal use pattern
u = User.create
e = Event.create
e.guests.create(:user => u, :confirmed => true)
With the ideal use pattern, e
has a Guest
with a reference to u
and u
has a reference to e
.
I know the has_many :through
line won't work. Any suggestions as to how to get similar functionality? I was thinking of using an after_create
callback in Guest
to add a reference to the Event
in User
, but that seems pretty hacky.
Maybe I've gone down the wrong path. Suggestions? Thanks.
You can just store the event ids in a array on the user.
You have to manage the array when the event changes or the user is removed from the event for some reason. But that is the trade off.
User.events can then be found with a single db call.
Look at observers to manage the association.
I ended up using callbacks in the models to accomplish I wanted. Here's what it looks like.
Edit: I just saw nodrog's answer. Yeah, using observers would probably have been neater, I didn't know about them. Thanks!
# user of the application
class User
has_and_belongs_to_many :events, inverse_of: nil, dependent: :nullify
end
# event that users can choose to attend
class Event
embeds_many :guests
index 'guests.user_id', unique: true
before_destroy :cleanup_guest_references
def cleanup_guest_references
self.guests.each do |guest|
guest.destroy
end
end
end
# guests for an event
class Guest
field :confirmed?, type: Boolean
embedded_in :event, :inverse_of => :guests
belongs_to :user
after_create :add_event_for_user
before_destroy :remove_event_for_user
private
def add_event_for_user
self.user.events.push(self.event)
end
def remove_event_for_user
self.user.events.delete self.event
self.user.save
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With