【问题标题】:Querying model by attribute of HABTM association按HABTM关联属性查询模型
【发布时间】:2016-04-19 03:13:46
【问题描述】:

我在用户和对话这两个模型之间有一个 HABTM 关联。 我希望能够查询登录用户的对话 (current_user.conversations),将另一个用户的 id 传递给它,并让它返回一个由两个用户共享的对话(如果存在的话)。 (一个额外的好处是让查询在不存在时创建一个。)

关联工作正常,因此我可以通过@user.conversations@conversation.users 等实例变量访问关联的对象,因此我可以走很长的路并遍历每个对话对象并搜索每个对话对象中的用户关联...但是必须有一种有效的方法来构造这个查询。 我想做的是current_user.conversations.where(conversation.users.exists?(id: @user_id))Conversation.find(users: {id: @user_id AND current_user.id}) 之类的东西。

我想这有一个明显的答案,我一直在这里寻找类似的问题,但没有找到任何问题。浏览完 Rails API 文档后,我想我正在寻找的解决方案在某种程度上涉及.includes(),但我无法让它工作。

有什么建议吗?谢谢。

【问题讨论】:

  • 你能发布一个关于用户和对话之间模型关系的高级sn-p吗?对话是否对每个用户都有一个外键(例如sender_idrecipient_id)?

标签: ruby-on-rails ruby ruby-on-rails-4 rails-activerecord active-relation


【解决方案1】:

假设您有两个用户@sender@receiver,并且他们之间有一个(或更多)对话。查询他们共享对话的一种可能方法是使用 ActiveRecord 中的merge 函数。 merge会选择他们之间的对话交集:

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

请注意,结果将是一个集合,而不是一个单独的对话。在 SQL 中,这将转换为 INNER JOIN

如果您想修改此查询以创建不存在的对话,那么您可以使用first_or_create。顾名思义,first_or_create 返回集合中的第一项。如果集合为空,它将创建一个新对象。您可以将块传递给它以进一步控制新创建的对象:

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

您可以在 Rails 文档中找到有关 merge 的更多详细信息:http://apidock.com/rails/ActiveRecord/SpawnMethods/merge

【讨论】:

  • 谢谢,这正是我要找的东西!不过有一点需要说服,当我调用 @sender.conversations.merge(@receiver.conversations).first_or_create 的等价物时,对话不存在,它创建了对话,但只有 @sender 与之相关。我通过添加循环并声明 @sender.conversations.merge(@receiver.conversations).first_or_create do |conversation| conversation.users << @receiver end 来解决这个问题,这似乎可以正常工作,再次感谢!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    相关资源
    最近更新 更多