【问题标题】:RUBY ON RAILS: Why isn't typeahead autocomplete using searchkick/elasticsearch working?RUBY ON RAILS:为什么使用 searchkick/elasticsearch 的 typeahead 自动完成功能不起作用?
【发布时间】:2016-12-12 02:00:41
【问题描述】:

当我在 rails 控制台中运行自动完成功能时,它可以工作。但是当我在浏览器的搜索字段中输入时,没有显示自动完成结果的下拉菜单。这是我的代码。任何帮助表示赞赏。我对这一切都很陌生,并通过研究自学。

routes.rb

Rails.application.routes.draw do

   resources :search_suggestions
   devise_for :users

   resources :posts do

   collection do
    get 'search'
    get 'autocomplete'
   end

  resources :reviews, except: [:show, :index]

end

root to: 'posts#index'
# For details on the DSL available within this file, see      http://guides.rubyonrails.org/routing.html
end

post.rb

class Post < ApplicationRecord
belongs_to :user
has_many :reviews, dependent: :destroy
searchkick autocomplete: [:title]
has_attached_file :image, styles: { medium: "300x300#"}
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/

end

posts_controller.rb

class PostsController < ApplicationController
 before_action :set_post, only: [:show, :edit, :update, :destroy]
 before_action :authenticate_user!, except: [:index, :show]


 def search
 if params[:search].present?
  @posts = Post.search(params[:search])
 else
  @posts = Post.all.order("created_at DESC")
 end
 end

 def autocomplete
  render json: Post.search(params[:search], autocomplete: true, limit:  10).map(&:title)
 end

 # GET /posts
 # GET /posts.json
 def index
   @posts = Post.all.order("created_at DESC")
 end

 # GET /posts/1
 # GET /posts/1.json
 def show
 @reviews = Review.where(post_id: @post.id).order("created_at DESC")

if @reviews.blank?
  @avg_review = 0
else
  @avg_review = @reviews.average(:rating).round(2)
end

end

# GET /posts/new
def new
@post = current_user.posts.build
end

  # GET /posts/1/edit
def edit
end

  # POST /posts
  # POST /posts.json
def create
@post = current_user.posts.build(post_params)

respond_to do |format|
  if @post.save
    format.html { redirect_to @post, notice: 'Post was successfully created.' }
    format.json { render :show, status: :created, location: @post }
  else
    format.html { render :new }
    format.json { render json: @post.errors, status: :unprocessable_entity }
  end
end
end

# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
  if @post.update(post_params)
    format.html { redirect_to @post, notice: 'Post was successfully updated.' }
    format.json { render :show, status: :ok, location: @post }
  else
    format.html { render :edit }
    format.json { render json: @post.errors, status: :unprocessable_entity }
  end
 end
end

  # DELETE /posts/1
  # DELETE /posts/1.json
def destroy
@post.destroy
respond_to do |format|
  format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
  format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_post
  @post = Post.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def post_params
  params.require(:post).permit(:title, :content, :image)
end
end

posts.coffee

$("#search").typeahead({
name: "post",
remote: "/posts/autocomplete?search=%SEARCH"
});

autocomplete.haml

= render 'layouts/header'

_header.haml

%nav.navbar.navbar-default.navbar-fixed-top
.container-fluid
    .navbar-header
        %button.navbar-toggle.collapsed(type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false")
            %span.sr-only Toggle navigation
            %span.icon-bar
            %span.icon-bar
            %span.icon-bar

        = link_to "Brand", root_path, class: "navbar-brand"

    .collapse.navbar-collapse#bs-example-navbar-collapse-1
        %ul.nav.navbar-nav.navbar-right
            - if user_signed_in?

                %li
                    = link_to current_user.username, edit_user_registration_path

                %li
                    = link_to 'new', new_post_path 

                %li
                    = link_to '', destroy_user_session_path, :method => :delete, data: { confirm: 'Are you sure you want to log out?' }, class: "  glyphicon glyphicon-off"

            - else
                %li
                    = link_to "Sign Up", new_user_registration_path
                %li
                    = link_to "Sign In", new_user_session_path

        = form_tag search_posts_path, method: :get, class: "navbar-form navbar-left", role: "search" do
            .input-group(style="max-width:181px;")
                = text_field_tag :search, params[:search], placeholder: "search", id: "search", name: "search", class: "form-control", autocomplete: "off"
                %span.input-group-btn 
                    %button.glyphicon.glyphicon-search.btn.btn-default(type="button") 


%script
    $('.glyphicon-search').click(function(){ $('.navbar-left').submit()});

【问题讨论】:

  • 我对coffeescript不感兴趣,但你的posts.coffee不是无效coffeescript吗?

标签: ruby-on-rails autocomplete searchkick


【解决方案1】:

您的posts.coffee 文件是javascript 而不是coffeescript。

您可以将 javascript 插入 this converter 以获取此咖啡脚本输出:

$('#search').typeahead
  name: 'post'
  remote: '/posts/autocomplete?search=%SEARCH'

其他说明

  • coffeescript 上的空格和缩进对语法规则至关重要(这就是我不使用它的原因)。每当我使用 coffeescript 时,我都会将其直接从转换器中复制出来,以确保不会弄乱间距和缩进。

  • 您的另一个选择是将posts.coffee 更改为posts.js,这样您就可以保留您的javascript

  • 根据您是否使用jquery-turbolinks gem,您还需要在typeahead 函数起作用之前添加$(document).ready 检查

    你的 javascript 会变成:

    $(function() {
      $("#search").typeahead({
        name: "post",
        remote: "/posts/autocomplete?search=%SEARCH"
      });
    });
    

    或等效的咖啡脚本:

    $ ->
      $('#search').typeahead
        name: 'post'
        remote: '/posts/autocomplete?search=%SEARCH'
      return
    

【讨论】:

    【解决方案2】:

    请仔细阅读这段代码并查看我的修改,我留下了相关部分(其他一切都还好)

    posts_controller.rb

     def autocomplete
      render json: Post.search(params[:search], autocomplete: true, limit:  10).map(|post|{title: post.title})
     end
    

    posts.js

    var ready;
    ready = function() {
        var engine = new Bloodhound({
            datumTokenizer: function(d) {
                console.log(d);
                return Bloodhound.tokenizers.whitespace(d.title);
            },
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            remote: {
                url: '/posts/autocomplete?search=%SEARCH',
                wildcard: '%QUERY'
            }
        });
    
        var promise = engine.initialize();
    
        $('#search').typeahead(null, {
            name: 'post',
            displayKey: 'title',
            source: engine.ttAdapter()
        });
    }
    
    $(document).ready(ready);
    $(document).on('page:load', ready);
    

    我不知道为什么需要这种奇怪的预先输入语法,但它确实有效。 看看你应该如何形成你的 json 响应,以及如何在客户端读取它的正确方法。

    您应该查看这个精彩的指南: https://rubyplus.com/articles/4031-Autocomplete-using-Typeahead-and-Searchkick-in-Rails-5

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2018-01-10
      • 1970-01-01
      • 2017-01-18
      • 2018-12-11
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多