Ruby on Rails: поиск ассоциации has_many с внутренним объединением и другими условиями - PullRequest
0 голосов
/ 08 февраля 2011

Я давно искал это, и я нигде не могу найти ответ.У меня есть базовая функция поиска, чтобы найти дома, все работает, и до сих пор основная часть для получения домов выглядит примерно так (условия, например):

@houses = House.all(
    :conditions => ["houses.province_id = ? AND open_houses.date > ? AND houses.surface = ?", "4", "Tue, 08 Feb 2011", "125"],
    :select => 'distinct houses.*',
    :joins => "INNER JOIN open_houses ON open_houses.house_id = houses.id" )

Теперь у меня естьэто has_many ассоциация для спецификации дома (например, балкон, бассейн и т. д.). Для этого у меня есть стандартные настройки.Таблица с именами спецификаций и таблица с house_id и spec_id.

Но теперь мне нужно добавить их в функцию поиска.Так что кто-то может найти дом с бассейном и балконом.

Я уверен, что есть решение, но я просто не знаю, где его вставить в код и как ... Google просто получаетмне на подобные страницы, но не на страницы, объясняющие в точности это.

Вот как выглядят мои параметры:

Parameters: {"dateto"=>"", "commit"=>"ZOEKEN!", "pricefrom"=>"", "location"=>"", "province_id"=>"4", "rooms"=>"", "datefrom"=>"", "surface"=>"125", "utf8"=>"✓", "priceto"=>"", "filters"=>{"by_specifications"=>["2", "5", "10"]}, "house_category_id"=>""}

Надеюсь, кто-то может помочь, если что-то неясно, дайте мне знать.

Спасибо

РЕДАКТИРОВАТЬ: Ок, я получил его на работу!Спасибо большое!

Есть только одна маленькая проблема: дом обнаруживается, если для дома существует одна из спецификаций .. Так что это запрос ИЛИ-ИЛИ, но я хочу И-И ..

Таким образом, если пользователь ищет балкон и гараж, дом должен отображаться только в том случае, если оба они существуют для дома. Что я сделал сейчас, так это: для каждой искомой спецификации выполняется запрос ... (кодниже)

Мне интересно, это правильный путь?Потому что это работает, но я получаю двойные совпадения .. (я фильтрую их, используя "uniq") Проблема с uniq заключается в том, что я не могу заставить "will_paginate" работать с ним ..

Этомой окончательный код:

def index
  ActiveRecord::Base.include_root_in_json = false

  # I'm creating conditions with a function I made, PM me for the code..
  conditions = createConditions( createParameters( ) );

  query = House.includes( :open_houses ).where( conditions )

  unless params[:specifications].blank?
    query = query.joins( :house_specifications )
    query = query.group( 'open_houses.id' )
    query = query.where( 'house_specifications.specification_id' => params[:specifications] )
    query = query.order( 'count(open_houses.id) DESC' )
    # query = query.having( 'count(open_houses.id) = ?', [params[:specifications].length.to_s] )
  end

  query = query.order( (params[:sort].blank?)? "open_houses.date ASC, open_houses.from ASC" : params[:sort] )

  if params[:view] == "list"
    page = params[:page] unless params[:page].blank?
    @houses = query.all.uniq.paginate( :page => page || "1", :per_page => 5 )
  else
    @houses = query.all.uniq
  end

  respond_to do |format|
    format.html
    format.js
  end
end

Спасибо за помощь, очень ценю!

1 Ответ

1 голос
/ 08 февраля 2011

Попробуйте это (Rails 3):

House.joins(:houses_specifications).
      where('houses_specifications.specification_id' => params[:by_specifications]).
      where(...).all

У вас может быть несколько вариантов if и case для добавления фильтров, group_by's, ограничений и т. Д., Прежде чем вы запустите этот final .all для запроса.

house_query = House.where(:pink => true)
unless params[:by_specifications].blank?
  house_query = house_query.joins(:houses_specifications).
                            where('houses_specifications.specification_id' => params[:by_specifications])
end
...
@houses = house_query.all

Редактировать: Новая и улучшенная версия, которая не запрашивает непосредственно в соединительной таблице на предмет читабельности, group_by на различимость и пересекается, чтобы получить дома со всеми спецификациями.

query = House.joins(:open_houses).where(conditions)

unless params[:specifications].blank?
  query = query.joins(:specifications).
                group('houses.id').
                where(:specifications => params[:specifications]).
                having('count(*)=?', params[:specifications].count)
end

if params[:view] == "list"
  @houses = query.all.paginate(:page => params[:page])
else
  @houses = query.all
end

Вы можете изменить «наличие» на «порядок», чтобы сначала получить те, у кого самые подходящие характеристики.

...