Rails Autocomplete Jquery (crowdint): выберите .uniq, не работающий в области действия, избегая дубликатов

Компании можно заполнять автоматически, просматривая записи, которые у меня уже есть. Используя гем https://github.com/crowdint/rails3-jquery-autocomplete, я добавил

autocomplete :company, :name, :scopes => [:distinct]

к моему контроллеру и в моей модели у меня есть:

scope :distinct, lambda { select("companies.name").uniq }

Используя термин «Мерс», моя система по-прежнему возвращает все 5 записей для «Мерседес-Бенц». SQL:

35mCompany Load (4.0ms)[0m  SELECT DISTINCT companies.name, companies.id FROM "companies" WHERE (LOWER(companies.name) ILIKE 'merce%') ORDER BY companies.name ASC LIMIT 10

Различные вещи, которые я пробовал:

select(:name).uniq  => Not unique values
distinct("companies.name") => Wrong number of arguments
group(:id, :name) => Not unique values
group(:id, :name).uniq  => Not unique values

Однако использование оператора select в контроллере (без автозаполнения) работает:

@companies = Company.select(:name).uniq => Perfect results

Ищете объяснение того, как сделать правильный запрос в этом драгоценном камне.


person Michael Schmitz    schedule 21.10.2012    source источник


Ответы (3)


Запрос, сгенерированный этим камнем:

Company Load (4.0ms)  SELECT DISTINCT companies.name, companies.id FROM "companies" WHERE (LOWER(companies.name) ILIKE 'merce%') ORDER BY companies.name ASC LIMIT 10

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

def get_autocomplete_select_clause(model, method, options)
  table_name = model.table_name
  (["#{table_name}.#{model.primary_key}", "#{table_name}.#{method}"] + (options[:extra_data].blank? ? [] : options[:extra_data]))
end

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

  1. Создайте запрос с подзапросом, идея состоит в том, чтобы создать первый запрос, который возвращает уникальные результаты, а затем внешнее соединение с идентификаторами таблицы и возвращает уникальные имена со своими идентификаторами.

  2. В вашем контроллере переопределите действие, которое извлекает результаты, чтобы оно делало все, что вы хотите. На самом деле этот гем добавляет действие autocomplete_model_attribute в ваш контроллер с помощью метапрограммирования (см. исходный код).

Надеюсь, это поможет, дайте мне знать, если это поможет. Дайте мне знать, если вам нужна дополнительная информация.

person chischaschos    schedule 23.10.2012
comment
Спасибо большое. Ваше объяснение было абсолютно правильным, затем я пошел по второму пути, переопределив контроллер. Я опубликую свое решение ниже, чтобы другие могли его увидеть. - person Michael Schmitz; 06.11.2012

Как уже сказал Chischaschos выше, переопределение действия контроллера — лучший способ. Поскольку я использую PostgreSQL на Heroku, мне нужно было пойти по более сложному маршруту, разработанному Туссом (Тоддом Хассом):

Когда мне нужно пользовательское автозаполнение, выходящее за рамки функций текущего плагина (например, выбор отдельных объектов), я реализую свой собственный метод автозаполнения на контроллере. Это просто заменяет вызов «autocomplete:organization,:city», который вы обычно вводите в свой контроллер. Например, для автозаполнения «отдельных» городов я делаю это:

def autocomplete_organization_city
 term = params[:term]
 if term && !term.empty?
  items = Organization.select("distinct city").
      where("LOWER(city) like ?", term.downcase + '%').
      limit(10).order(:city)
 else
 items = {}
 end
render :json => json_for_autocomplete(items, :city)
end

Существует также более короткое решение для пользователей SQLite, которое намного короче. Найдите исходную ветку здесь: https://github.com/crowdint/rails3-jquery-autocomplete/issues/25

person Michael Schmitz    schedule 06.11.2012

Лучший подход:

  # model
  scope :distinct_on_name, lambda {
      select('DISTINCT ON (models.name) models.name, models.id')
  }
  # controller
  autocomplete :model, :name, scopes: [:distinct_on_name]
person Marcin Nowicki    schedule 05.05.2015