FAST AUTOCOMPLETE SEARCH TERMS - RAILS
Bài đăng này đã không được cập nhật trong 3 năm
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ụ:
- Với đường dẫn: http://loacalhost:3000/autocomplete. Ta có thể thấy trạng thái của soulmate
- Với đường dẫn: http://0.0.0.0:3000/autocomplete/search?types[]=nouns&limit=6&term=pro ta được
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:
Để 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.
8. Tài liệu tham khảo và source code
All rights reserved