Расширенный поиск со многими ко многим в Rails 4 - PullRequest
0 голосов
/ 19 апреля 2019

У меня есть список объектов недвижимости, каждый из которых имеет свои особенности.Затем у меня есть 2 таблицы:

  • real_estates, для хранения всех объектов недвижимости, добавленных пользователями.
  • re_home_features, для хранения всех функций по умолчанию, добавленных администратором, таких как pool, closet,офис, сад и множество других функций, которые может иметь недвижимое имущество

Одно и то же real_estate может иметь много функций И ​​одна и та же функция может иметь много объектов недвижимости.Я создал эти модели:

real_estate.rb

class RealEstate < ActiveRecord::Base
    has_many :real_estate_home_features
    has_many :re_home_features, as: :home_features, through: :real_estate_home_features, dependent: :destroy
end

re_home_features.rb

class ReHomeFeature < ActiveRecord::Base
    has_many :real_estate_home_features
    has_many :real_estates, through: :real_estate_home_features
end

real_estate_home_feature.rb

class RealEstateHomeFeature < ActiveRecord::Base
    belongs_to :real_estate
    belongs_to :re_home_feature
end

При этом отношение многих ко многим работает нормально.

У меня есть поиск объектов недвижимости с некоторыми параметрами, такими как:

  • Количество жилых комнат
  • Количество ванных комнат
  • Цена продажи (от минимальной до максимальной)
  • Общая площадь (от минимальной до максимальной)
  • Код недвижимости
  • и много других параметров

Мой поиск такой:

real_estates_controller.rb

def search
    r = real_estates
    r = r.where(code: params['code']) if params['code'].present?
    r = r.where(city_name: params['city']) if params['city'].present?
    r = r.where(garage: params['garage']) if params['garage'].present?
    r = r.where(restrooms: params['restrooms']) if params['restrooms'].present?

    r = r.paginate(:page => params[:page], :per_page => 10)

    r
end

Этот поиск тоже работает нормально.Никаких проблем с этим, потому что все параметры находятся в одной таблице real_estates.

Но теперь поиск стал немного сложнее.Я должен искать недвижимость с определенными особенностями.Пример: я хочу, чтобы все объекты недвижимости, в которых было 4 туалета, 2 машины в гараже и пул .

В моем примере, поиск объектов недвижимости с 4 туалетами и 2 автомобилями вернулся вмне 50 объектов недвижимости, но только 15 из этих объектов имеют пул.

Как я могу отфильтровать эти 50 объектов недвижимости, чтобы показать только записи, связанные с «функцией пула»?

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

Я ценю любую помощь!

environment

rails -v: Rails 4.2.1
ruby -v: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
so: Ubuntu 16.04.5 LTS
localhost database: MySQL (development)
server database: Postgres (production)

EDIT 1

На основе ответа @jvillian я изменю свой контроллер, добавив в запрос JOIN.

if params['home_features'].present? && params['home_features'].any?
    r = r.joins(:re_home_features).where(re_home_features: {id: params['home_features']}).distinct(:id)
end

В моих тестах у меня было:

params['home_features'] = [1 , 2, 3]

У меня есть 1 объект недвижимости, который имеет эти 3 функции.Но, по мнению, я один и тот же сайт показывал 3 раза.Если я добавил отчет, недвижимость показывается только один раз.НО ... Если я изменю параметры на:

params['home_features'] = [1 , 2, 3, 500]

, у меня нет недвижимости с этими 4 функциями, но результаты совпадают.Без отчетливости, недвижимость показана 3 раза.С помощью наркомана недвижимость показывается один раз.Ожидаемый результат - нулевые результаты, потому что я хочу недвижимость со всеми выбранными функциями.

Но я думаю, что мы почти у цели!Я предоставлю некоторую информацию о моих моделях:

таблица real_estates

id | title      | description | code | city_name      | garage | ...
 7 | Your House | Awesome...  | 1234 | Rio de Janeiro | 4

таблица re_home_features

id | name
 1 | Pool
 2 | Garden
 3 | Tenis court
 4 | Closet

таблица real_estate_home_features - связь многих со многими

id | real_estate_id | re_home_feature_id
 1 |              7 |                  1
 2 |              7 |                  2
 3 |              7 |                  3

Если я запускаю:

r = r.joins(:re_home_features).where(re_home_features: {id: [1,2,3,500]}).distinct(:id)

Я получил эти запросы (консоль rails):

SELECT DISTINCT `real_estates`.* FROM `real_estates` INNER JOIN `real_estate_home_features` ON `real_estate_home_features`.`real_estate_id` = `real_estates`.`id` INNER JOIN `re_home_features` ON `re_home_features`.`id` = `real_estate_home_features`.`re_home_feature_id` WHERE `re_home_features`.`id` IN (1, 2, 3, 500)

И это возвращает 1 результат.Идентификатор недвижимости 7. Если я удалю отчет, у меня будет 3 результата: та же недвижимость, 3 раза.

Ожидаемый результат - ноль.Если params['home_features'] = [1 , 2, 3] Я ожидаю 1 результат.

РЕДАКТИРОВАТЬ 2

Этот метод соединения работает, но он возвращает как запрос "ИЛИ".В моем случае мне нужен запрос соединения с «И».Запрос должен быть: «Вернуть все объекты недвижимости, которые имеют особенности 1, 2 и 3».

Tks!

1 Ответ

1 голос
/ 19 апреля 2019

Я не уверен, что это «расширенный поиск».Поиск по объединенным моделям описан в руководстве под 12.1.4 Задание условий в соединенных таблицах .Это выглядело бы примерно так:

real_estates.joins(:re_home_features).where(re_home_features: {feature_name: 'pool'})

Естественно, это, вероятно, не будет работать точно, потому что вы не очень много говорите нам о том, как найти «функцию пула».Но это должно дать вам правильное направление.

Кстати, причина этого:

params['home_features'] = [1 , 2, 3, 500]

возвращает записи, которые имеют any из home_features, потому что он использует 'или».Если вы хотите real_estates с all home_features, тогда вам нужны 'и'.Вы можете поискать информацию об этом.

Думаю, я бы попробовал что-то вроде:

def search

    r = real_estates.joins(:re_home_features)

    %i(
      code
      city_name
      garage
      restrooms
    ).each do |attribute|
      r = r.where(attribute => params[attribute]) unless params[attribute].blank?
    end

    params[:home_features].each do |home_feature_id|
      r = r.where(re_home_features: {id: home_feature_id})
    end unless params[:home_features].blank?

    r = r.uniq
    r = r.paginate(:page => params[:page], :per_page => 10)
    r

end

ПРИМЕЧАНИЕ. Я изменил params[:city] на params[:city_name], чтобы сделать этот первый итератор each чище,Вам нужно будет изменить свое мнение, если вы хотите сделать это таким образом.Если вы не хотите делать это таким образом, вы можете вернуться к уже не использовавшемуся итератору подходу.

Это не проверено, поэтому я не уверен, что он будет работать точно так же, какпредставил.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...