Search and Autocomplete in Rails Apps
Bài đăng này đã không được cập nhật trong 6 năm
Tìm kiếm là một trong những tính năng phổ biến nhất mà chúng ta có thể tìm thấy trên bất kỳ trang web nào ngày nay. Có rất nhiều giải pháp để thực hiện đưa tính năng ngày một cách dễ dàng vào trong ứng dụng của bạn. Trong bài viết này sẽ giới thiệu về tìm kiếm với Postgres bằng cách sử dụng gem pg_search và kết hợp với plugin select2. Bài viết sẽ giới thiệu qua ví dụ tìm kiếm công nhân với tính năng autocomplete. Cụ thể bài viết sẽ giới thiệu:
- xây dựng một tính năng tìm kiếm căn bản
- xây dựng một tính năng autocomplete để hiển thị kết quả tìm kiếm theo tên người dùng
Xây dựng ứng dụng
Để bắt đầu chúng ta tạo một ứng dụng sử dụng postgresql
rails new Autocomplete --database=postgresql
Tạo một PG database và cài đặt config/database.yml
đúng, dùng dotenv-rails để lưu tên và mật khẩu kết nối với Postegres database.
Gemfile
# ...
group :development do
gem 'dotenv-rails'
end
Để cài đặt chúng, chúng ta chạy
$ bundle install
và tạo một tệp trong thư mục gốc của project như sau .env
PG_USER: 'user'
PG_PASS: 'password'
và ignore chúng khi dùng quản lý phiên bản git .gitignore
.env
Cuối cùng là cài đặt cấu hình của bạn có thể giống như sau
development:
adapter: postgresql
database: autocomplete
host: localhost
user: < %= ENV['PG_USER'] %>
password: < %= ENV['PG_PASS'] %>
Tạo một bảng và lưu một vài thông tin của người dùng
$ rails g model User name:string surname:string
$ rails db:migrate
Để tạo dữ liệu mẫu, chúng ta có thể sử dụng Faker Gemfile
# ...
group :development do
gem 'faker'
end
Để cài đặt chúng, chạy lại $ bundle install
Chúng ta có thể tạo user với tên ngẫu nhiên như sau
db/seeds.rb
50.times do
User.create({name: Faker::Name.first_name,
surname: Faker::Name.last_name})
end
Để khởi tạo chúng chỉ cần chạy $ rails db:seed
Cuối cùng là giới thiệu một root route, controller với index action và một view để hiển thị tất cả các người dùng
config/routes.rb
# ...
resources :users, only: [:index]
root to: 'users#index'
userscontroller.rb
class UsersController < ApplicationController
def index
@users = User.all
end
end
views/users/index.html.erb
<ul>
< %= render @users %>
</ul>
views/users/user.html.erb
<li>
< %= user.name %> < %= user.surname %>
</li>
Tìm kiếm Users
Chúng ta sẽ làm một form trên đầu trang chủ để tìm kiếm người dùng theo tên hoặc họ. Bắt đầu với form có thể như sau views/users/index.html.erb
< %= form_tag users_path, method: :get do %>
< %= text_field_tag 'term', params[:term], placeholder: "Enter user's name or surname" %>
< %= submit_tag 'Search!' %>
< % end %>
Giờ là xử lý ở backend, chúng ta sẽ sử dụng pg_search
Gemfile
# ...
gem 'pg_search'
Đừng quên để cài đặt, chúng ta chạy $ bundle install
Pg_search hỗ trợ 2 chế độ: multisearchable và pg_search_scope. Ở đây ta sẽ sử dụng kiểu thứ 2 đó là tạo một scope để tìm kiếm.
Bắt đầu để sử dụng, chúng ta phải include PgSearch module
models/user.rb
# ...
include PgSearch
pg_search_scope :search_by_full_name, against: [:name, :surname]
Trong ví dụ này :name
và :surname
sẽ được đưa vào để tìm kiếm
userscontroller.rb
# ...
if params[:term]
@users = User.search_by_full_name(params[:term])
else
@users = User.all
end
Vậy là chúng ta có thể sử dụng tính năng tìm kiếm một cách đơn giản rồi.
Tính năng search autocomplete
Một tính năng phổ biến có thể dễ thấy đó là autocomplete search. Chúng ta có thể sử dụng select2 để dễ dàng đạt được yêu cầu Gemfile
# ...
gem 'select2-rails'
gem 'underscore-rails'
Select2 là một plugin biến những trường nhập đơn giản thành một trường nhập linh hoạt với người dùng, còn Underscore.js sẽ cùng cấp một vài phương thức để có thể dễ dàng hơn. Để sử dụng thư viện, chúng ta phải khai báo như sau javascripts/application.js
//= require underscore
//= require select2
//= require messages
stylesheets/application.scss
@import 'select2';
Giờ ta tạo một route, controller , view mới: config/routes.rb
# ...
resources :messages, only: [:new]
messagescontroller.rb
class MessagesController < ApplicationController
def new
end
end
views/messages/new.html.erb
<%= form_tag '' do %>
< %= label_tag 'to' %>
< %= select_tag 'to', nil, style: 'width: 100%' %>
< % end %>
Trường select không có bất kỳ giá trị nào, nó sẽ là phần hiển thị động kết quả dựa trên thông tin người dùng nhập vào. Để thực thi việc autosearch, chúng ta sẽ phải lấy giá trị cho trường select này mỗi khi người dùng gõ ký tự bất kỳ để tìm kiếm. Công việc này sẽ được điều khiển bởi đoạn javascript đơn giản sau:
jQuery(document).on 'turbolinks:load', ->
$('#to').select2
ajax: {
url: '/users'
data: (params) ->
{
term: params.term
}
dataType: 'json'
delay: 500
processResults: (data, params) ->
{
results: _.map(data, (el) ->
{
id: el.id
name: "#{el.surname}, #{el.name}"
}
)
}
cache: true
}
escapeMarkup: (markup) -> markup
minimumInputLength: 2
templateResult: (item) -> item.name
templateSelection: (item) -> item.name
Tiếp theo chúng ta phải sử lý kết quả search động mà server cần phải tìm và trả về userscontroller.rb
# ...
def index
respond_to do |format|
if params[:term]
@users = User.search_by_full_name(params[:term]).with_pg_search_highlight
else
@users = User.all
end
format.json
format.html
end
end
views/users/index.json.jbuilder
json.array! @users do |user|
json.id user.id
json.name user.name
json.surname user.surname
end
views/users/index.json.jbuilder
json.array! @users do |user|
json.id user.id
json.full_name user.pg_search_highlight.html_safe
json.name user.name
json.surname user.surname
end
Để xử lý kết quả trả về từ server, chúng ta thực thi processResults
ở trên như sau
processResults: (data, params) ->
{
results: _.map(data, (el) ->
{
name_highlight: el.full_name
id: el.id
name: "#{el.surname}, #{el.name}"
}
)
}
Vậy là hoàn thành một chứ năng đơn giản nhưng rất phổ biến và thông dụng ngày nay. Bạn có thể tìm mã code chương trình hoàn chỉn ở đây
Refs
All rights reserved