Reputation: 118
i got a simple messaging system running between two users.
the user who is creating a conversation
gets a record i can access via User.find(sender_id).conversation.last
, the recipient however gets a => nil if i try to access User.find(recipient_id).conversation.last
(ofc i replaced recipient_id and sender_id with the actual id).
However, both user get the messages associated with the conversation and can chat. I am using foreign keys according to the tutorial of Dana Mulder on Medium. i think this is weird because i expect that both users ( the reciever and the sender ) should be able to access the record for the conversation they are into. is there a way to achieve that?
my models:
User.rb
has_many :conversations, :foreign_key => :sender_id, dependent: :destroy
has_many :messages, through: :conversations
Conversation.rb
belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'
has_many :messages, dependent: :destroy
Message.rb
belongs_to :conversation
belongs_to :user
the conversations controller:
conversations_controller.rb
def create
if Conversation.between(params[:sender_id],params[:recipient_id]).present?
@conversation = Conversation.between(params[:sender_id], params[:recipient_id]).first
else
@conversation = Conversation.create!(conversation_params)
end
redirect_to conversation_messages_path(@conversation)
end
do you have an idea how to make the conversation accessible for both users? (it is accessible but not in the way i need it to).
thanks in advance!
Upvotes: 1
Views: 146
Reputation: 15838
Your user association with conversations is only looking for sender_id
has_many :conversations, :foreign_key => :sender_id, dependent: :destroy
The recipient user is looking for conversation with his id as sender_id
and not as recipient_id
.
I think you can fix that by adding a join model between users and conversations instead of a conversation just belonging to a sender and a recipient (though you should save those references anyway).
Something like
class ConversationsUsers < ....
belongs_to :user
belongs_to :conversation
end
class User < ...
has_many :conversations_users
has_many :conversations, through: :conversations_users
has_many :started_conversations, class_name: 'Conversation', foreign_key: :sender_id
has_many :received_conversations, class_name: 'Conversation', foreign_key: :recipient_id
end
class Conversation < ...
has_many :convesations_users
end
For each Conversation you'll have two records on conversations_users table, one for each user. Now both users can query all the conversations independant of being a sender or a recipient (and you can have any number of participants on a conversation too if you plan to extend it!).
You'll have to create some records manually though, after creating a Conversation you could have an after callback to create two conversation_user object one for each user.
Another option is to just use a method
def conversations
Conversation.where(sender_id: id).or(Conversation.where(recipient_id: id))
end
but you won't be able to use joins/includes/etc.
EDIT: To get all messages, add another method:
def messages
conv_ids = conversations.pluck(:id)
Message.where(conversation_id: conv_ids)
end
then you can this to get all read messages for example
current_user.messages.where(read: true)
Upvotes: 2