Rails:过滤has_many_through关联,其中存在所有已检查的关联

时间:2015-01-28 03:23:20

标签: ruby-on-rails activerecord

我正在尝试构建一个复选框过滤器,它会进一步减少每个额外复选框的结果数量,其中每个复选框表示has_many中关联的关系。

我有一个包含以下型号的应用程序:

  • 医院
  • HospitalFeatures
  • 功能

以下是关联:

class Hospital < ActiveRecord::Base
  has_many :hospital_features
  has_many :features, through: :hospital_features
end

class HospitalFeature < ActiveRecord::Base
  belongs_to :hospital
  belongs_to :feature
end

class Feature < ActiveRecord::Base
  has_many :hospital_features
  has_many :hospitals, through: :hospital_features
end

我有一个复选框表单,其中列出了所有可用功能。

<%= label_tag("helipad", "Helipad") %>
<%= check_box_tag("features[]", "helipad" %>

<%= label_tag("telesurgery", "Telesurgery") %>
<%= check_box_tag("features[]", "telesurgery" %>

<%= label_tag("emergency room", "Emergency Room") %>
<%= check_box_tag("features[]", "emergency room" %>

我试图像在购物网站上那样进行过滤,其中每个复选框都会过滤到仅具有所有已检查功能的医院。

我现在正在使用的查询:

hospitals = Hospital.joins(:features).where(features: {name: features} )

恰恰相反。每个检查的额外框都会增加结果数量,因为它会返回带有任何一个已检查功能的医院,而不是具有所有已检查功能的医院。

所以如果你检查&#34;直升机停机坪&#34;和&#34;远程手术&#34;,它应该只返回医院同时使用&#34;直升机停机坪&#34;和&#34;远程手术&#34;而不是任何医院都有&#34;直升机停机坪&#34;或者&#34;远程手术&#34;。

环顾四周,似乎无法找到明显的解决方案。我感谢任何帮助。提前谢谢。

4 个答案:

答案 0 :(得分:1)

也许这不是最美丽的解决方案,但它对我有用。

Hospital.joins(:features).where(features: {name: features}).group('hospitals.id').having("count(*) >= ?", features.size)

答案 1 :(得分:1)

有一个解决方案。首先将医院连接到功能,然后进行过滤,其中'features.name in(?)'将features数组插入到查询中。

因此,对于该医院的每个功能,这将返回同一家医院。因此,如果该列表包含4个功能,并且医院全部为4个,那么该医院将被退回4次。同样,如果它只有4个特征中的3个,它将返回3次。

然后按医院ID分组,并添加“HAVING COUNT(*)”等于过滤后的功能数。

然后结果是:

  hospitals = Hospital.joins(:features)
    .where('features.name in (?)', searched_features)
    .group("hospitals.id")
    .having('COUNT(*) = ?', searched_features.length)

希望最终帮助别人。如果有人发现更优雅的方式,请告诉我。

答案 2 :(得分:0)

我认为有很多选择可以做到这一点 - 对我来说效果很好的是Sunspot Solr过滤方面。 Railscasts很好地解释了它:http://railscasts.com/episodes/278-search-with-sunspot

答案 3 :(得分:0)

使用我的Where Exists gem:

result = Hospital.all
features.each do |feature|
  result = scope.where_exists(:features, name: feature)
end