Question

I'm having a lot of issues with my messaging system. I would love some help. It works fully, except the User Message relation. I'm attempting to relate authored_messages to User and received_messages to User. The roadblock from doing this is that received_messages is supposed to go through two different models (ConversationUser and Conversation), whereas authored_messages should be a direct relationship using the message's user_id field. Here she is:

Models

User:

class User < ActiveRecord::Base

has_many(
:conversation_users, 
inverse_of: :user,
dependent: :destroy
)

has_many(
:conversations, 
through: :conversation_users
)

# has_many :messages   ?

# has_many(            ?
# :received_messages,
# class_name: "Messages",
# through: :conversations,
# source: :conversation_users
# )

Message:

class Message < ActiveRecord::Base

belongs_to :user                               # ?

belongs_to :recipient, class_name: "User"      # ?

belongs_to(
:conversation, 
inverse_of: :messages
)

has_many(
:conversation_users, 
through: :conversation
)

accepts_nested_attributes_for :conversation

Conversation:

class Conversation < ActiveRecord::Base  

has_many(
:messages, 
inverse_of: :conversation
)

has_many(
:conversation_users, 
inverse_of: :conversation
)

has_many(
:users, 
through: :conversation_users
)

accepts_nested_attributes_for :messages

ConversationUser (a join model):

class ConversationUser < ActiveRecord::Base

belongs_to(
:user, 
inverse_of: :conversation_users
)

belongs_to(
:conversation, 
inverse_of: :conversation_users
)

has_many(
:messages,
through: :conversation
)

delegate :users, to: :conversation
accepts_nested_attributes_for :conversation

Migrations

User

# None involved with messaging

Message

t.integer :user_id
t.integer :conversation_id
t.text :body

Conversation

# None, except the :id field. It helps relate messages and conversation_users

ConversationUser

t.integer :user_id
t.integer :conversation_id

It seems to me that I'd be adding something like this (how do I associate one model twice to another), but I'm having a hard time applying this to my models. And to further clarify how these associations work, this is a really simplified visual:

users--->conversation_users
  :             |
  :             |
  V             V
messages<---conversation

I'd really, really appreciate any help I can get, and hopefully this question will help other people dealing with complex associations!

EDIT

I forgot to mention it, but this messaging system can have as many recipients (conversation_users) as the sender decides. (when the sender creates a new conversation)

Was it helpful?

Solution 2

I ended up figuring it out via further trial and error. I was making it much harder than it was. Here are the correct changes for the User and Message classes and the relations between them:

Message

class Message < ActiveRecord::Base

belongs_to :user                # This

belongs_to(
:conversation, 
inverse_of: :messages
)

has_many(
:conversation_users, 
through: :conversation
)

has_many(                       # This
:recipients, 
class_name: "User", 
through: :conversation_users,
source: :user
)

accepts_nested_attributes_for :conversation

User

class User < ActiveRecord::Base

has_many(
:conversation_users, 
inverse_of: :user,
dependent: :destroy
)

has_many(
:conversations, 
through: :conversation_users
)

has_many :messages               # This

has_many(                        # This
:received_messages, 
class_name: "Message", 
through: :conversations,
source: :messages
)

The associations I marked with # This are the four relations I was having trouble connecting in the first place. This messaging system is a unique four-model messaging system that supports (hypothetically) limitless conversation users. Its behavior is not unlike many other social network messaging systems out there. It is fully functional, and any of these four class objects can be accessed from any other related class object. I hope this Q/A will serve as a great reference for anyone trying to build a similar messaging system. Cheers!

OTHER TIPS

How do you know whether a message is sent or received?

In your message model, you're only referencing user_id and conversation_id. You'd typically want recipient_id and sender_id instead of just user_id:

class User < ActiveRecord::Base
    has_many :conversation_users, inverse_of: :user, dependent: :destroy
    has_many :conversations, through: :conversation_users
end

class Conversation < ActiveRecord::Base
    has_many :conversation_users
    has_many :users, through: conversation_users

    has_many :sent_messages, class: "Message", through: :conversations, foreign_key: "sender_id", source: :user
    has_many :received_messages, class: "Message", through: :conversations, foregin_key: "recipient_id", source: :user
end

class Message < ActiveRecord::Base
    belongs_to :conversation
    belongs_to :sender, class_name: "User", primary_key: "sender_id"
    belongs_to :recipient, class_name: "User", primary_key: "recipient_id"
end

messages
t.integer :sender_id
t.integer :recipient_id
t.integer :conversation_id
t.text :body

This should yield:

@user.conversations[x].sent_messages
@user.conversations[x].received_messages
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top