0

So, I have a web app that allows two users to message each other. A "recipient" and a "sender". When two users first try to message each other, it works great. But if a user tries to message a different person, Action Cable doesn't create a new conversation and it returns them to the conversation they had with the first person. This is happening because my "if Conversation.between" is returning true when it should be returning FALSE! I have a screenshot below: (ignore the '&', that was just put in to get an error)

Picture of conversation.between returning true when it should be FALSE:

enter image description here

Anyways my code is below and if someone could solve this headache I've been dealing with it would be GREATLY appreciated. thanks

Conversations Controller:

class ConversationsController < ApplicationController
before_action :authenticate_user!

def index
 @conversations = Conversation.involving(current_user)
end

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

private

def conversation_params
  params.permit(:sender_id, :recipient_id)
end
end

Messages_controller:

class MessagesController < ApplicationController
before_action :authenticate_user!
before_action :set_conversation

def index
 if current_user == @conversation.sender || current_user == @conversation.recipient
  @other = current_user == @conversation.sender ? @conversation.recipient : @conversation.sender
  @messages = @conversation.messages.order("created_at DESC")
 else
  redirect_to conversations_path, alert: "You don't have permission to view this."
 end
 end

 def create
  @message = @conversation.messages.new(message_params)
  @messages = @conversation.messages.order("created_at DESC")

 if @message.save
  ActionCable.server.broadcast "conversation_#{@conversation.id}", message: render_message(@message)
  redirect_to conversation_messages_path(@conversation)
 end
 end

 private

  def render_message(message)
   self.render(partial: 'messages/message', locals: {message: message})
  end

  def set_conversation
   @conversation = Conversation.find(params[:conversation_id])
  end

  def message_params
   params.require(:message).permit(:conteny, :user_id)
  end
  end

Conversation Model:

class Conversation < ApplicationRecord
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
validates_uniqueness_of :sender_id, :recipient_id

scope :involving, -> (user) {
 where("conversations.sender_id = ? OR conversations.recipient_id = ?", user.id, user.id)
 }

scope :between, -> (user_A, user_B) {
 where("(conversations.sender_id = ? OR conversations.recipient_id = ?) OR conversations.sender_id = ? OR conversations.recipient_id = ?", user_A, user_B, user_B, user_A)
 }
end

Message Model:

class Message < ApplicationRecord
belongs_to :user
belongs_to :conversation

validates_presence_of :content, :conversation_id, :user_id
after_create_commit :create_notification

def message_time
 self.created_at.strftime('%B %d, %Y')
end

 private

  def create_notification
   if self.conversation.sender_id == self.user_id
    sender = User.find(self.conversation.sender_id)
    Notification.create(content: "New message from #{sender.fullname}", user_id: self.conversation.recipient_id)
   else
    sender = User.find(self.conversation.recipient_id)
    Notification.create(content: "New message from #{sender.fullname}", user_id: self.conversation.sender_id)
   end
 end
 end

Please help, I've been struggling for about a week now. thanks.

moondaisy
  • 4,303
  • 6
  • 41
  • 70
Colin Steidtmann
  • 417
  • 1
  • 4
  • 10

1 Answers1

0

Assuming your scope:

Conversation.between(user_A, user_B)

...means "find all Conversation records where user_A and user_B have sent to each other (regardless which of them the sender is), then...

The following should work:

scope :between, -> (user_a_id, user_b_id) {
  where('(sender_id = ? AND recipient_id = ?) OR (sender_id = ? AND recipient_id = ?)', user_a_id, user_b_id, user_b_id, user_a_id)
}

Which is the same as:

scope :between, -> (user_a_id, user_b_id) {
  where(
    sender_id: user_a_id, recipient_id: user_b_id
  ).or(
    where(
      sender_id: user_b_id, recipient_id: user_a_id
    )
  )
}
Jay-Ar Polidario
  • 6,463
  • 14
  • 28