+1

FAST AUTOCOMPLETE SEARCH TERMS - RAILS

1. Giới thiệu

Bạn muốn làm một chức năng tìm kiếm thông minh, có thể hiển tự động hiển thị kết quả ngay khi đang gõ chữ và gọi ý các kết quả. Một chức năng tìm kiếm giống với Facebook có thể cho kết quả bao gồm cả User cả Group.

Hãy tham khảo sample app dưới đây.

2. GETTING STARTED

Tạo sample app

$ rails new fast-autocomplete

Thêm gem

gem 'faker', github: 'stympy/faker'
gem 'rack-contrib'
gem 'soulmate', :require => 'soulmate/server'

Sau đó chạy bundle

3. Tạo model

Tạo 2 model: Noun và Verb

$ rails g scaffold noun name:string
$ rails g scaffold noun name:string

Sau đó chạy migrate

rake db:migrate

4. Thêm và xóa dữ liệu soulmate với các hàm callback

File app/models/noun.rb

class Noun < ActiveRecord::Base
  after_save :load_into_soulmate
  before_destroy :remove_from_soulmate

  validates_uniqueness_of :name

  private
  def load_into_soulmate
    loader = Soulmate::Loader.new("nouns")
    loader.add("term" => name, "id" => self.id, "data" => {
      "link" => Rails.application.routes.url_helpers.noun_path(self)
    })
  end

  def remove_from_soulmate
    loader = Soulmate::Loader.new("nouns")
    loader.remove("id" => self.id)
  end
end

File app/models/verb.rb

class Verb < ActiveRecord::Base
  after_save :load_into_soulmate
  before_destroy :remove_from_soulmate

  validates_uniqueness_of :name

  private
  def load_into_soulmate
    loader = Soulmate::Loader.new("verbs")
    loader.add("term" => name, "id" => self.id, "data" => {
      "link" => Rails.application.routes.url_helpers.verb_path(self)
    })
  end

  def remove_from_soulmate
    loader = Soulmate::Loader.new("verbs")
    loader.remove("id" => self.id)
  end
end

Tạo dữ liệu trong file seeds.rb

# create 500 nouns
puts "Creating 'nouns'"
500.times do
  Noun.create(name: Faker::Name.name)
end

# create 500 verbs
puts "Creating 'verbs'"
500.times do
  Verb.create(name: Faker::Name.name)
end

Sau đó chạy

$ rake db:seed

5. Tải dữ liệu trong App

File config/routes.rb

Rails.application.routes.draw do
  mount Soulmate::Server, :at => "/autocomplete"

  resources :verbs
  resources :nouns
end

Ta có thể query soulmate bằng đường dẫn /autocomplete.

Ví dụ:

6. Tạo giao diện tìm kiếm sử dụng jquery và soulmate.js

Thêm //= require jquery.soulmate trong file app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require jquery.soulmate
//= require turbolinks
//= require_tree

Thêm *= require soulmate trong app/assets/stylesheets/application.css

*= require_tree .
*= require soulmate
*= require_self
*/

Thêm file soulmate.js trong app/assets/javascripts

var ready = function(){
  var render, select;

  render = function(term, data, type) {
    return term;
  }

  select = function(term, data, type){
    // populate our search form with the autocomplete result
    $('#search').val(term);

    // hide our autocomplete results
    $('ul#soulmate').hide();

    // then redirect to the result's link
    // remember we have the link in the 'data' metadata
    return window.location.href = data.link
  }

  $('#search').soulmate({
    url: '/autocomplete/search',
    types: ['users','groups'],
    renderCallback : render,
    selectCallback : select,
    minQueryLength : 2,
    maxResults     : 5
  })

}
// when our document is ready, call our ready function
$(document).ready(ready);

// if using turbolinks, listen to the page:load event and fire our ready function
$(document).on('page:load', ready);

Thêm file soulmate.css app/assets/stylesheets

#soulmate {
  background-color: #fafafa;
  border: 1px solid #bbb;
  display: none;
  font: 12px/14px "Helvetica Neue", Helvetica,   Arial, sans-serif;
  font-weight: normal;
  list-style: none;
  margin: 0 0 0 10px;
  padding: 0;
  position: absolute;
  text-shadow: 0 0 0 white;
  /* play around with the top and left properties for correct positioning */
  top: 201px;
  left: 460px;
  width: 579px;
  z-index: 1000;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  -ms-border-radius: 4px;
  -o-border-radius: 4px;
  -khtml-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  -khtml-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  -ms-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  -o-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}

#soulmate .soulmate-type-container {
  border-top: 1px solid #ddd;
}

#soulmate .soulmate-type-container:first-child {
  border-top: none;
}

#soulmate .soulmate-type-suggestions {
  border-left: 1px solid #ddd;
  float: right;
  list-style: none;
  padding: 5px 0;
  width: 490px;
  letter-spacing: 0.5px;
}

#soulmate .soulmate-suggestion {
  color: #111;
  cursor: pointer;
  font-weight: 500;
  font-size: 13px;
  padding: 5px 0 6px 12px;
  text-decoration: none;
}

#soulmate .soulmate-suggestion.focus {
  color: white;
  margin-left: -1px;
  margin-right: -1px;
  padding-left: 13px;
  position: relative;
  text-shadow: 0 1px 1px #32629b;
  z-index: 1;
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  -khtml-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  -ms-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  background: #545454;
  background: -moz-linear-gradient(top, #545454 0, #444444 100%);
  background: -webkit-gradient(linear, 0 0, 0 100%, from(#545454), to(#444444));
  -ms-filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#545454,endColorstr=#444444)";
  filter: progid: DXImageTransform.Microsoft.gradient(startColorstr=#545454,endColorstr=#444444);
}

#soulmate .soulmate-type {
  background-color: white;
  color: #333;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 11px;
  letter-spacing: 0.5px;
  margin-right: 490px;
  padding: 10px 10px 0 10px;
  text-align: right;
  text-transform: capitalize;
  vertical-align: top;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  -ms-border-radius: 5px;
  -o-border-radius: 5px;
  -khtml-border-radius: 5px;
  border-radius: 5px;
  zoom: 1;
}

#soulmate .soulmate-type:before, #soulmate .soulmate-type:after {
  content: "";
  display: table;
}

#soulmate .soulmate-type:after {
  clear: both;
}

Cuối cùng là cần file jquery.soulmate.js trong app/assets/javascripts jquery.soulmate.js

7. Tạo form search

Tạo controller home/index

$ rails g controller home index

Thêm trong file routes.rb

root 'home#index'

Thêm view app/views/home/index.html.erb

<div class="container">
  <h2>Search Nouns and Verbs</h2>
  <%= form_tag do %>
    <%= text_field_tag "search", nil, placeholder: "Search", autocomplete: :off %>
  <% end %>
</div>

Thêm css cho view

home.css.scss

// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

.container {
  width: 500px;
  margin: 0 auto;
  padding: 100px;
  text-align: center;
}

#search{
  width: 400px;
  padding: 10px;
}

li.soulmate-suggestion{
 text-align: left;
}

Ta được form search như sau: 3.png

Để hiển thị kết quả tìm kiếm ta thêm file home.js

var ready = function(){
  var render, select;

  render = function(term, data, type) {
    return term;
  }

  select = function(term, data, type){
    // populate our search form with the       autocomplete result
    $('#search').val(term);

    // hide our autocomplete results
    $('ul#soulmate').hide();

    // then redirect to the result's link
    // remember we have the link in the 'data' metadata
    return window.location.href = data.link
  }

  $('#search').soulmate({
    url: '/autocomplete/search',
    types: ['nouns','verbs'],
    renderCallback : render,
    selectCallback : select,
    minQueryLength : 2,
    maxResults : 5
  })
}

// when our document is ready, call our ready function
$(document).ready(ready);

// if using turbolinks, listen to the page:load event and fire our ready function
$(document).on('page:load', ready);

Khi đó sẽ hiển thị được các kết quả mà ta muốn. 4.png

8. Tài liệu tham khảo và source code


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.