7

我有 2 个模型

class User < AR
 has_many :friends
end

class Friend < AR
  # has a name column
end

我需要找到所有与“乔”和“杰克”都是朋友的用户

知道如何在 Rails 中做到这一点吗?

4

3 回答 3

3

一种选择是将每个名称作为单个 INNER JOINS 的参数。在 SQL 中,它会是这样的:

SELECT users.* FROM users
INNER JOIN friends AS f1 
    ON users.id = f1.user_id 
    AND f1.name = 'Joe'
INNER JOIN friends AS f2 
    ON users.id = f2.user_id 
    AND f2.name = 'Jack'

由于它是 INNER JOINS,它只会显示用户表可以同时使用 f1 和 f2 连接的结果。

要在 Rails 中使用它,也许可以这样做:

class User < AR
  has_many :friends

  def self.who_knows(*friend_names)
    joins((1..friend_names.length).map{ |n| 
      "INNER JOIN friends AS f#{n} ON users.id = f#{n}.user_id AND f#{n}.name = ?" }.join(" "),
      *friend_names)
    })
  end
end

然后你可以这样调用:

@users = User.who_knows("Joe", "Jack")
于 2012-05-21T08:23:31.353 回答
1

可能User.all(:joins => :friends, :conditions => ["friends.name IN (?,?)", "Joe", "Jack"], :group => "users.id")的方式:然后遍历数组以找到有 2 个朋友的用户。

这是我尝试为自己解决类似问题时得到的最佳解决方案。如果你找到了使用纯 sql 或 ActiveRecord 的方法——请告诉我!

于 2012-05-21T08:18:54.710 回答
1

尽管按照 DanneManne 的建议使用硬编码 SQL 通常会起作用,并且可能是您想要的方式,但它不一定是可组合的。一旦你硬编码了一个表名,你可能会遇到将它组合到 ActiveRecord 可能决定为表别名的其他查询的问题。

因此,以一些额外的复杂性为代价,我们可以使用一些 ARel 来解决这个问题,如下所示:

f = Friend.arel_table
User.
  where(:id=>f.project(:user_id).where(f[:name].eq('Joe'))).
  where(:id=>f.project(:user_id).where(f[:name].eq('Jack')))

这将使用一对子查询来完成这项工作。

我相当肯定还有一个使用连接的 ARel 解决方案,但是我可以弄清楚如何在 ARel 中编写该查询,而不是如何使用该查询作为 ActiveRecord 查询的基础来获取用户模型实例。

于 2012-05-21T16:23:01.897 回答