0
votes

I'm working on a basic private messaging system for my application. I started with this tutorial on Medium.

I discovered an issue though. It returns all conversations, not just the ones that the current user is actually involved in. The view only shows the ones you're in but all the records are there. Obviously that is horrible if you have more than a handful of users.

I've tweaked the controller to what I thought was the solution but I'm still getting all records so I'm thinking the issue is in the model.

Conversations Controller

class ConversationsController < ApplicationController

 before_action :authenticate_user!
 before_action :set_conversation, only: [:destroy]

 def index
  @user = current_user
  @conversations = Conversation.where(:sender_id == @user.id || :recipient_id == @user.id)
 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

Conversation Model

class Conversation < ActiveRecord::Base
 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, :scope => :recipient_id

 scope :between, -> (sender_id,recipient_id) do
  where(sender_id: [sender_id,recipient_id], recipient_id: [sender_id,recipient_id]) 
 end

 def unread_message_nr_for(user_id)
     messages.where('messages.read = ?', false).where('messages.user_id != ?', user_id).count
 end

end

Conversation View

  <div class="ibox-content no-side-borders">
      <% @conversations.each do |conversation| %>
      <div class="conversation-member">
       <% if conversation.sender_id == current_user.id || conversation.recipient_id == current_user.id %>
       <% if conversation.sender_id == current_user.id %>
        <% recipient = User.find(conversation.recipient_id) %>
       <% else %>
        <% recipient = User.find(conversation.sender_id) %>
       <% end %>

            <span class="<%= 'current-conversation' if (params['conversation_id'].to_i == conversation.id) %>">
            <% if recipient.avatar.present? %>
            <%= image_tag(recipient.avatar_url(:navigation), class: "img-circle m-r-xs") %>
          <% end %>
              <%= link_to recipient.first_name + " " + recipient.last_name, conversation_messages_path(conversation)%>
            </span>
            <% if conversation.unread_message_nr_for(current_user.id) > 0 %>
              <span class="badge-inline">
                <%= conversation.unread_message_nr_for(current_user.id) %>
              </span> 
            <% end %>
       <% end %>
     </div>
     <% end %>
  </div>

Conversations Schema

  create_table "conversations", force: :cascade do |t|
    t.integer  "sender_id"
    t.integer  "recipient_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

How can I get only the conversations where the current user is the sender_id or the recipient_id?

1
Instead of params[:sender_id],params[:recipient_id], shouldnt it be conversation_params[:sender_id] and conversation_params[:recipient_id]?Amit Badheka

1 Answers

1
votes

You can't use ruby in the where clause. See the guides for more info

Conversation.where("sender_id = ? OR recipient_id = ?", @user.id, @user.id)