Rails:过滤 has_many_through 关联,其中所有选中的关联都存在

Rails: Filter on has_many_through association where all checked associations exist

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

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

以下是协会:

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} )

相反。每个额外的复选框都会增加结果的数量,因为它 return 医院具有任何一个被选中的特征,而不是医院具有所有被选中的特征。

因此,如果您检查 "helipad" 和 "telesurgery",它应该 return 只有同时具有 "helipad" 和 "telesurgery" 的医院,而不是任何具有 "helipad" 和 "telesurgery" 的医院=41=] 或 "telesurgery".

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

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

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

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

找到解决办法了。首先将医院加入到特征中,然后过滤 'features.name in (?)' 将特征数组插入到查询中。

因此,这将 return 同一家医院的每个功能都与该医院具有的相同。因此,如果列表包含 4 个特征,而一家医院拥有全部 4 个特征,则该医院将被 returned 4 次。同样,如果它只有 4 个特征中的 3 个,它会 return 3 次。

然后您按医院 ID 分组并添加 'HAVING COUNT(*)' 等于过滤后的特征数。

那么最终结果是:

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

希望这最终能帮助到其他人。如果有人找到更优雅的方法来做到这一点,请告诉我。

使用我的 Where Exists gem:

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