简体   繁体   中英

Querying model by attribute of HABTM association

I have an HABTM association between two models, User and Conversation. I want to be able to query the logged-in user's conversations ( current_user.conversations ), passing it another user's id, and have it return a conversation that is shared by both users, if one exists. (an additional perk would be to have the query create one if one doesn't exist.)

The associations are working fine, so I can access the associated objects through instance variables like @user.conversations and @conversation.users , so I could go the long way and loop through each conversation object and search the user associations in each of them... But there must be an efficient way to construct this query. What I would like to be able to do is something like current_user.conversations.where(conversation.users.exists?(id: @user_id)) or something like Conversation.find(users: {id: @user_id AND current_user.id}) .

I imagine there is an obvious answer to this, and I've been searching around here for similar questions but haven't found any. After looking through the Rails API docs, I imagine that the solution I'm looking for involves .includes() in some way, but I can't get it working.

Any advice? Thanks.

Suppose you have two users @sender and @receiver , and there is one (or perhaps more) conversation between them. One possible way to query their shared conversations is by using the merge function in ActiveRecord. merge will select the intersection of conversations between between them:

@shared_conversations = @sender.conversations.merge(@receiver.conversations)

Note that the result will be a collection, not an individual conversation. In SQL this would translate to an INNER JOIN .

If you wanted to amend this query to create the conversation if it didn't exist, then you can use first_or_create . Like its name implies, first_or_create returns the first item in the collection. If the collection is empty, it will create a new object. You can pass it a block for further control over the newly created object:

@shared_conversations = @sender.conversations.merge(@receiver.conversations).first_or_create do |conversation|
  conversation.title = "#{@sender.first_name}'s conversation"
end

You can find more details on merge in the Rails docs: http://apidock.com/rails/ActiveRecord/SpawnMethods/merge .

尝试 current_user.conversations.includes(:users).where(user.id:current_user.id)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM