1

I am building a sort of "non instant messaging system". My system consists of many Users, Chats, and Messages.

  • Users can have many Chats
  • Chats can only belong to two different Users
  • Messages belong to one User and one Chat

The way I designed it is:

rails g model Chat user1:references user2:references
rails g model Message user:references chat:references

And then in my models/chat.rb i do:

# models/chat.rb
class Chat < ApplicationRecord
  belongs_to :user1, :class_name => 'User'
  belongs_to :user2, :class_name => 'User'
end

My models/message.rb model

# models/message.rb
belongs_to :user
belongs_to :chat

And my models/user.rb model

# models/user.rb
has_many :chats
has_many :messages, through: :chats

All of this modeling makes sense to me, but i just cant get it to work. I need to be able to do something like User.find(1).chats and have it return all the user's chats. Also Chat.find(1).users would be nice. User.find(1).messages is not that much trouble since it's pretty standard relationship, but what about the others? what am i missing? I have read forum through forum but i can't seem to get any solution to work on my specific case.

Jake Worth
  • 5,490
  • 1
  • 25
  • 35
GuidoMedina
  • 117
  • 1
  • 9
  • Suggested changes: chats have many messages, messages belong to a chat. Chats have and belong to many users, Users have and belong to many Chats. I think this would support your use cases. https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association – Jake Worth Jul 16 '21 at 01:56
  • 1
    Is there a behavioral difference between Chat's user1 and user2, or are you just trying to limit it to two users? You're probably better off making it Chat.has_many :users. That will solve most of your association issues, and give you the flexibility to increase the number of users per chat. You can also validate that Chat only has two users: https://stackoverflow.com/questions/2263267/limit-number-of-objects-in-has-many-association – TonyArra Jul 16 '21 at 10:03
  • @TonyArra there really isn't a behavioral difference between the two, you are right i could just limit it to two users with a simple has_many, which would also allow me to, in the future, think of group chats. I will consider your solution, for now i came up with a custom method " users " inside chat, that returns the users linked to that specific chat when i do chat.users. Thank you. – GuidoMedina Jul 16 '21 at 11:11
  • @JakeWorth I was really trying to a void a has_and_belongs_to_many (just to practice the has_many :through) but right now i'm using has_many :through and i really see no practical usage of it. it's just there "sitting" not being useful. Thanks. – GuidoMedina Jul 16 '21 at 11:13
  • To build on what @TonyArra said, 'has_many' (or 'has_and_belongs_to_many ', possibly) would be the conventional way to model this. I think this is a good case of where YAGNI falls short; if your chat works like most chats, you're eventually going to want chats with more than two (or less than two) users. – Jake Worth Jul 16 '21 at 12:40
  • 1
    Yes @JakeWorth, i will model it that way, thank you for the reassurance(also, i didn't know about YAGNI). Any of you can make a comment so i can mark it as the right solution! – GuidoMedina Jul 16 '21 at 12:46

1 Answers1

1

I would suggest these changes (with assistance from @TonyArra):

  • Chats have_many messages
  • Message belongs_to a chat
  • Chats have_and_belongs_to_many (or belongs_to) users
  • Users have_and_belongs_to_many (or have_many) chats

This would be the conventional way to model this, and I think it would support your use cases.

I mentioned YAGNI in the comments because the OP mentioned chats only having two users. YAGNI (you aren't going to need it, so don't built it now) is a great principle. However, many chat programs support more than two users, and sometimes just one user. You could argue that building the data model with that consideration in mind is pragmatic.

Great further reading on that subject: Preemptive Pluralization is (Probably) Not Evil

Jake Worth
  • 5,490
  • 1
  • 25
  • 35
  • This is a good alternative, i actualy settled my mind on Chat -> has_many :users, through: :messages, chat being the join model between users and messages, but it's a team project and we need to move on, so we will be using the solution i don't like, Yay! Very interesting read too, i will check it out, thanks again! – GuidoMedina Jul 16 '21 at 14:20
  • @GuidoMedina that's an interesting design. It would mean that a chat can't exist between two users until one sends a message to the other, and that sending a message to the chat automatically adds that user to it. That fits more of a forum model (async communication) than a live chat, since it would mean that there's no way for someone to "leave" the chat. – TonyArra Jul 16 '21 at 15:20
  • @TonyArra You hit the nail on the head let me tell you... We are building an asyncronous chat (don't ask why). And i based that modelling in a Post-Comments-Users design, so yeah, you are right it fits a forum model! It's a very good thinking exercise, but a real pain to design! I didn't even think about "what if one of them leaves the chat? what if one of them deletes it?" – GuidoMedina Jul 16 '21 at 16:12