Как в Rails настроить гем Twitter Typeahead.js для Rails?

bootstrap-typeahead-rails README от gem переносит вопрос на README от Twitter для typeahead.js. Это оставляло желать лучшего.

Этот ответ на переполнение стека содержит подробные инструкции для twitter-typeahead-rails gem. Я хотел увидеть что-то подобное для драгоценного камня bootstrap-typeahead-rails.


person klenwell    schedule 03.05.2015    source источник


Ответы (2)


Вот мой гид. Он следует примеру @ihaztehcodez. В этом примере предполагается модель Thing, и в представление индекса добавляется форма для поиска things по атрибуту модели name.

Несколько заметок:

  • Я использую Rails 4 (4.2.1).
  • Для поисковых запросов я использую гем Searchlight.
  • Для шаблонов я использую гем slim-rails.
  • Стилизация остается в качестве упражнения для разработчика.

Добавить гем в гемфайл

# Gemfile

# Typeahead gem
gem 'bootstrap-typeahead-rails'

# Optional gems
gem 'searchlight'
gem 'slim-rails'

Включить файлы с вводом текста в манифесты активов

Таблица стилей (SASS)

# app/assets/stylesheets/application.scss

  *= require bootstrap-typeahead-rails

Javascript

# app/assets/javascripts/application.js

//= require bootstrap-typeahead-rails
//= require_tree .

Добавить маршрут typeahead в файл маршрутов

# config/routes.rb

  get 'things/typeahead/:query' => 'things#typeahead'

Добавить код javascript с опережающим вводом текста

# app/assets/javascripts/things.js

var onReady = function() {

  // initialize bloodhound engine
  var searchSelector = 'input.typeahead';

  var bloodhound = new Bloodhound({
    datumTokenizer: function (d) {
      return Bloodhound.tokenizers.whitespace(d.value);
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,

    // sends ajax request to remote url where %QUERY is user input
    remote: '/things/typeahead/%QUERY',
    limit: 50
  });
  bloodhound.initialize();

  // initialize typeahead widget and hook it up to bloodhound engine
  // #typeahead is just a text input
  $(searchSelector).typeahead(null, {
    displayKey: 'name',
    source: bloodhound.ttAdapter()
  });

  // this is the event that is fired when a user clicks on a suggestion
  $(searchSelector).bind('typeahead:selected', function(event, datum, name) {
    //console.debug('Suggestion clicked:', event, datum, name);
    window.location.href = '/things/' + datum.id;
  });
};

Добавьте соответствующие методы/действия в контроллер

# app/controllers/things_controller.rb

  # GET /things
  # GET /things.json
  def index
    @search = ThingSearch.new(search_params)
    @things = search_params.present? ? @search.results : Thing.all
  end

  # GET /things/typeahead/:query
  def typeahead
    @search  = ThingSearch.new(typeahead: params[:query])
    render json: @search.results
  end

  private

  def search_params
    params[:thing_search] || {}
  end

Добавить форму поиска в представление индекса (используя SLIM gem)

# app/views/things/index.html.slim

div.search.things
  = form_for @search, url: things_path, method: :get do |f|
    div.form-group.row
      div.col-sm-3
      div.col-sm-6
        = f.text_field :name_like, {class: 'typeahead form-control',
            placeholder: "Search by name"}
        = f.submit 'Search', {class: 'btn btn-primary'}
      div.col-sm-3.count
        | Showing <strong>#{@things.length}</strong> Thing#{@things.length != 1 ? 's' : ''}

Создать класс поиска Searchlight

Если вы предпочитаете не использовать Searchlight, используйте в модели интерфейс запросов ActiveRecord.

# app/searches/thing_search.rb

class ThingSearch < Searchlight::Search
  search_on Thing.all

  searches :name_like, :typeahead

  # Note: these two methods are identical but they could reasonably differ.
  def search_name_like
    search.where("name ILIKE ?", "%#{name_like}%")
  end

  def search_typeahead
    search.where("name ILIKE ?", "%#{typeahead}%")
  end
end
person klenwell    schedule 03.05.2015
comment
Так красиво и основательно! Не могли бы вы использовать pluralize в представлении index в последней строке? Отличный пост. - person steve klein; 04.05.2015
comment
@steveklein Я согласен, что линия уродлива. Я хотел бы сделать номер жирным, но не знаю, как это сделать с помощью pluralize помощника. Есть рекомендации? - person klenwell; 04.05.2015
comment
О, я понимаю, что вы имеете в виду. Я не уверен, что это лучше, но вы можете split вывести pluralize и просто выделить число жирным шрифтом. С вашим, если все в порядке, поскольку к тому времени, когда вы добираетесь до точки зрения, вы, вероятно, знаете, что имеете дело с вещами, а не с волами (например). - person steve klein; 04.05.2015
comment
@klenwell откуда thing_search в def search_params params[:thing_search] || {} end? - person Sooraj; 05.01.2016
comment
@SoorajChandran Хороший вопрос и хороший взгляд. form_for search в индексном представлении должно быть form_for @search. (Я исправил код выше.) В моя ссылка, форма поиска была частичной, поэтому @search было передано как search, отсюда и ошибка. Таким образом, thing_search происходит от этой формы, к которой, как мне кажется, Searchlight добавляет немного волшебства. Вы можете найти реальную реализацию, на которой это было основано, в моем recruiters_controller здесь. - person klenwell; 05.01.2016
comment
Важное примечание: search_on был удалено из Searchlight 4.0.0 и выше. Вместо этого вам нужно определить метод def base_query; Thing.all; end - person GMA; 04.02.2016
comment
О, и вы также можете удалить строку searches :name_like, :typeahead начиная с 4.0.0 — теперь она выводится автоматически на основе имен методов экземпляра в классе TypeSearch. И search в методах должно быть query, например. query.where("name ILIKE ?", "%#{name_like}%") - person GMA; 04.02.2016
comment
Любые решения для ошибки undefined local variable or method 'things_path'? - person laimison; 24.04.2017
comment
Привет, @klenwell, в настоящее время я занят решением той же проблемы, связанной с привязкой typeahead.js к моему пользовательскому контроллеру с методом autocomplete, и я продолжаю получать неопределенность для datum.id, где данные передаются в качестве параметра. - person Thato Sello; 15.11.2020

Ответ @klenwell устарел. Вот как я заставил это работать:

Я использую:

  • Начальная загрузка v3.3.6
  • ищейка 0.11.1
  • bootstrap3-typeahead 3.1.0
  • jQuery 2.2.0

Моя модель называется Destination.

приложение/модели/destination_search.rb:

class DestinationSearch < Searchlight::Search

  def base_query
    Destination.all
  end

  def search_typeahead
    query.where("name ILIKE", "%#{typeahead}%")
  end

end

контроллер:

class DestinationsController < APIController

  def typeahead
    render json: DestinationSearch.new(typeahead: params[:query]).results
  end

end

JS:

var bloodhound = new Bloodhound({
  datumTokenizer: function (d) {
    return Bloodhound.tokenizers.whitespace(d.value);
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace,

  remote: {
    url: '/api/destinations/typeahead?query=%QUERY',
    wildcard: "%QUERY",
  },
  limit: 10
});
bloodhound.initialize();

$(document).ready(function () {
  $(".destination-typeahead").typeahead({
    source: function (query, process) {
      return bloodhound.search(query, process, process);
    },
  });
});

и в представлении:

<%= text_field_tag :destination, class: "destination-typeahead" %>

Кажется немного хакерским, когда я дважды передаю метод process в bloodhound.search — это потому, что Bloodhound#search принимает в качестве аргументов два обратных вызова, один из которых работает с кэшированными/предварительно выбранными данными, а другой обрабатывает данные, полученные динамически через AJAX. Возможно, я не использую #search на 100% правильно, но этот подход работает, и это простое начало.

person GMA    schedule 04.02.2016
comment
Я новичок в этом и не понимаю, как ваше исправление вписывается в исходный ответ. Можете ли вы уточнить свой код просмотра, пожалуйста? как легфилдс вписывается в форму поиска кленвелла? - person theawesome; 09.02.2016
comment
К сожалению, leg_fields было чем-то специфичным для моей кодовой базы, что здесь не имеет значения. Я отредактировал это. Мой ответ не предназначен для того, чтобы вписаться в форму поиска klenwall - вам нужно будет разработать свою форму в зависимости от того, что именно вы пытаетесь сохранить. - person GMA; 10.02.2016
comment
Как настроить APIController? Это также имеет '/api' в URL-адресе. Было бы здорово получить больше объяснений. - person laimison; 24.04.2017