1

I have two sequel models user and event, which is currently handled by a single join table. Users can be invited to events, and these invitations have a status attached to them; this is handled by another join table.

class Event < Sequel::Model(:events)
  many_to_many :users
  many_to_many :invitations, :join_table => :events_invitations, :right_key => :user_id, :class => :User, :select=>[Sequel.expr(:users).*, :events_invitations__status]
end

class User < Sequel::Model(:users)
  many_to_many :events
  many_to_many :invitations, :join_table => :events_invitations, :right_key => :event_id, :class => :Event, :select=>[Sequel.expr(:events).*, :events_invitations__status]
end

I am able to create and access the associated invitations, but the changes are never saved (i'm assuming due to the way i've set up the many_to_many)

user = User.create(name: "bob")
event = Event.create(title: "super fete")
user.add_event(e)
event.add_invitation(e)

invite = user.invitations.first
# this returns a reference to the event, with the extra status column from the join table
# <Event @values={:id=>1, :title=>"fete", :owner_id=>nil, :user_id=>nil, :status=>"pending"}>
# does not actually save back to the table if I modify it...
invite[:status] = "accepted"

How should I model this so as to be able to see and set the status of invitations for users and events?

Nick Tomlin
  • 28,402
  • 11
  • 61
  • 90
  • See related: http://stackoverflow.com/questions/15672918/sequel-accessing-many-to-many-join-table-when-adding-association – Phrogz Feb 04 '15 at 22:28
  • I made in another question an answer https://stackoverflow.com/a/48139189/676874 where you can see, how you can adapt the many_to_many-relation to add additional parameters in your `add_invittion`. But to get the data you need a model. – knut Jan 07 '18 at 19:06

1 Answers1

1

First, some (ultimately unhelpful) basics.

Sequel is letting you treat the model like a hash, insofar as you can store extra read-only values on it. However, as with Sequel's hashes returned from a dataset, just setting the key does not update it. For example:

bob = DB[:users][name:'Bob']  #=> {:id=>1, :name=>"Bob"}
bob[:name] = 'Mary'
p bob                         #=> {:id=>1, :name=>"Mary"}
p DB[:users][1]               #=> {:id=>1, :name=>"Bob"}

This is true for Model instances as well:

bob = User[name:'Bob']  #=> #<User @values={:id=>1, :name=>"Bob"}>
bob[:name] = 'Mary'
p bob                   #=> #<User @values={:id=>1, :name=>"Mary"}>
p User[1]               #=> #<User @values={:id=>1, :name=>"Bob"}>
bob.name = 'Jerome'
p bob                   #=> #<User @values={:id=>1, :name=>"Jerome"}>
p User[1]               #=> #<User @values={:id=>1, :name=>"Bob"}>

For the Dataset, you need to update your dataset to change values in the database.

For the Model, you need to either update the values as above and then save your changes to that model instance (e.g. bob.save) or you need to use your instances to update it with new values (e.g. bob.update name:'Mary').


But really, you are abusing the many_to_many class and select values to make a thing that looks like an Event, but which is not. If 20 people are invited to the fête, it's incorrect to have 20 different "events" all named "super fete" but with differing status. Those aren't events, those are invitations.

You want an Invitation model to represent your join, associated with the join table. Then you can get an instance that has a status, and you can update it as you like. You can't update from the Event instance because it doesn't know anything about the events_invitations table or the status column, other than to fetch them when asked.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • That makes complete sense; having a model for the join table feels much more natural. I'm still struggling with how exactly to express the relationships within that model in terms of Sequel associations. If that's too much to cover in an update to the question I can ask another. – Nick Tomlin Feb 04 '15 at 23:49