Rails Active Admin - 如何仅过滤符合集合中所有已检查项目的记录

时间:2012-11-06 12:56:51

标签: ruby-on-rails activeadmin

我有一对多的用户与网络模型的关联。我的架构信息的相关部分如下。

# == Schema Information      
# Table name: users
#
#  id                     :integer         not null, primary key
#  name                   :string(255)

#
# Table name: networks
#
#  id         :integer         not null, primary key
#  user_id    :integer
#  uid        :string(255)
#  name   :string(255)
#  pub_url    :string(255)

我想使用网络模型的name属性过滤掉具有特定多个网络的用户。例如,如果我将facebook和foursquare作为过滤器检查,我想找回连接facebook和foursquare的用户。我目前的实现是传递一个数组,其中包含用户可以添加的网络名称,如下所示。

filter :networks_name, :as => :check_boxes,
:collection => %w(facebook twitter foursquare linkedin)

然而,这对过滤器使用OR条件,该过滤器检索具有任何已检查项目的用户。我真正想要的是满足所有检查项目的用户。 实现这一目标的正确方法是什么?

1 个答案:

答案 0 :(得分:4)

ActiveAdmin将meta_search用于其过滤器(https://github.com/ernie/meta_search):

filter :networks_name_all,
  :as => :check_boxes,
  :collection => %w(facebook twitter foursquare linkedin)

在您的用户模型中:

scope :networks_names_all_in, -> names {
  names.reduce(scoped) do |scope, name|
    subquery = User.select('`users`.`id`').
      joins(:networks).
      where('networks.name = ?', name)
    scope.where("`users`.`id` IN (#{subquery.to_sql})")
  end
}
search_methods :networks_name_all_in

这将为您创建一个很好的单个SQL查询,具有适当的连接和条件。

例如:

User.networks_name_all_in(["facebook", "twitter"])

将生成以下SQL请求:

SELECT *
FROM `users`
WHERE `users`.`id` IN (SELECT `users`.`id`
                       FROM `users`
                       INNER JOIN `networks`
                       ON `networks`.`user_id` = `users`.`id`
                       WHERE `networks`.`name` = 'facebook')
  AND `users`.`id` IN (SELECT `users`.`id`
                       FROM `users`
                       INNER JOIN `networks`
                       ON `networks`.`user_id` = `users`.`id`
                       WHERE `networks`.`name` = 'twitter')

更新:增加了功能范围。

更新2:使范围适应范围合并问题。