2015-01-28 2 views
1

Я пытаюсь создать фильтр флажка, который дополнительно уменьшает количество результатов с каждым дополнительным флажком, где каждый флажок представляет собой отношение в has_many через ассоциацию.Rails: Фильтр по has_many_through ассоциации, где существуют все проверенные ассоциации

У меня есть приложение со следующими моделями:

  • больницы
  • 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 

У меня есть чек -box, который перечисляет все доступные функции.

<%= 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" %> 

Я пытаюсь фильтровать, как и на торговом месте, где каждый Отмеченное окно дополнительные фильтры только в больницах с ALL проверенными функциями.

Запрос я использую сейчас:

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

делает противоположное. Каждый проверенный флажок увеличивает количество результатов, так как он возвращает больницы с ЛЮБОЙ одной из проверенных функций, а не больниц со ВСЕМИ проверенными функциями.

Так что, если вы проверите «вертолетную площадку» и «телеоперацию», она должна вернуть только больницы с «вертолетной площадкой» и «телеоперацией», а не с любой больницей с «вертолетной» или «телеоперацией».

Посмотрел вокруг и не может найти очевидного решения. Я ценю любую помощь. Заранее спасибо.

ответ

1

Возможно, это не самое красивое решение, но оно сработало для меня.

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

Я думаю, что проблема этого метода состоит в том, что у меня нет никаких проблем Добавление и состояние с помощью точечной нотации. Я могу сделать это, просто добавив другое 'where'. Проблема заключается в том, что я заранее не знаю, сколько ящиков будет проверено, поэтому я не знаю, сколько 'where' включить. Если есть способ динамически добавлять произвольное число 'where', это было бы правильным решением. – KenneyE

+0

Извините, я забираю это обратно. Это АР: 'Hospital.joins (особенность): .гд (3) .гд ("? Feature_id =", 4)' производит этот SQL: 'SELECT "больница" * от "больниц" Inner. JOIN «hospital_features» ON «hospital_features». «Hospital_id» = «больницы». Id «INNER JOIN» имеет функции «ON». «Id» = «hospital_features». «Feature_id» WHERE (feature_id = 3) AND (feature_id = 4) ' Это явно неверно, так как потребовалось бы, чтобы одна строка имела 2 отдельных объекта feature_ids, что невозможно. Я снова потерялся. – KenneyE

+1

Вторая попытка. Вы должны поместить это в другой ответ, чтобы я увидел изменение. Это в конечном итоге очень похоже на решение, которое я в конечном итоге с помощью которого был: больницы = Hospital.joins (: особенности) .гд ('features.name в()?, Searched_features) .group ("больницы .id ") .having ('COUNT (*) =?', search_features.length) Это возвращает ту же больницу для каждой функции, что и в больнице. Так что если список содержит 4 функции, а в больнице все 4, то больница будет возвращена 4 раза. Итак, вы группируете идентификатор больницы и добавляете «HAVING COUNT (*)», равное количеству фильтрованных функций. – KenneyE

0

Я думаю, что есть много вариантов для этого - тот, который хорошо сработал для меня, - это фильтрация Sunspot Solr с помощью граней. Railscasts объясняет это довольно хорошо: http://railscasts.com/episodes/278-search-with-sunspot.

0

Получено решение. Сначала присоединились больницы к функциям, а затем отфильтровали, где «features.name» в (?) »Интерполирует массив признаков в запрос.

Таким образом, это вернет ту же больницу для каждой функции, что у этой больницы. Так что если список содержит 4 функции, а в больнице все 4, то больница будет возвращена 4 раза. Аналогично, если бы у него было только 3 из 4 функций, он возвращал бы его 3 раза.

Итак, вы группируете идентификатор больницы и добавляете «HAVING COUNT (*)», равное количеству фильтрованных функций.

Тогда конечный результат существо:

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

Надеется, что это поможет кому-то еще в конце концов. Дайте мне знать, если кто-нибудь найдет более элегантный способ сделать это.

0

Используя мой Where Exists перл:

result = Hospital.all 
features.each do |feature| 
    result = scope.where_exists(:features, name: feature) 
end 
Смежные вопросы