3

I have a User model and a Conversation model. User has many conversations and Conversation has many users, so I use has_and_belongs_to_many relationship through join table :conversations_users. I use the method to return the conversation between specific users (by user id):

def find_conversation_between_users(ids)
  conversation = nil
  conversations = Conversation.all

  if conversations.present?
    conversations.each do |conv|
      next unless conv.user_ids == ids.sort

      conversation = conv
    end
  end
end


class Conversation < ApplicationRecord
  has_and_belongs_to_many :users
end

class User < ApplicationRecord
  has_and_belongs_to_many :conversations
end

It works but it won't be efficient if we would have thousands of conversations and it will take too much time to iterate over each of them. So I try to create the scope that returns the specific conversation by related user_ids [1 , 2, 3].

scope :by_user_id, ->(user_ids) { joins(:conversations_users).where([ conversations_users: { user_id: user_ids } ]) }

But it does not works.

demir
  • 4,591
  • 2
  • 22
  • 30
  • Would you be ready to change to `has_many: through`? If yes, I think I could give you solution. Basically there are no change in tables - just need to create `ConversationsUser` model. – matiss Oct 07 '19 at 17:53

1 Answers1

1

Try this way:

class Conversation < ApplicationRecord
  has_and_belongs_to_many :users
  scope :by_user_id, ->(ids) { joins(:users).where(users: { id: ids }).group(:id).having("count(*) >= ?", ids.size) }
end
demir
  • 4,591
  • 2
  • 22
  • 30
  • It works but incorrectly. For example, if I have: "Created the conversation with id=1 that has [1, 2] user_ids." "Created the conversation with id=2 that has [2, 3] user_ids." "Created the conversation with id=3 that has [1, 4] user_ids." and perform Conversation.by_user_id([1,2]), it returns conversations with ids: **1, 3, 1, 2**. but I need only with id **1**. – Pasha Bratanov Oct 09 '19 at 06:06
  • @PashaBratanov Hmm now I understand the problem. I updated the answer. – demir Oct 09 '19 at 07:40
  • @PashaBratanov You're welcome. Would you mark my answer as an answer and upvote it :) – demir Oct 09 '19 at 12:58