TÌM HIỂU RANSACK, GEM TÌM KIẾM CHO ỨNG DỤNG RAILS
Bài đăng này đã không được cập nhật trong 3 năm
Giới thiệu
Gem ransack cho phép người dùng xây dựng tìm kiếm cho ứng dụng của bạn. Tích hợp cả 2 hình thức tìm kiếm đơn giản và nâng cao, đồng thời còn giúp người dùng sắp xếp kết quả tìm kiếm.
Cài đặt
Thêm gem ransack vào trong gemfile, chạy bundle.
gem "ransack"
Sử dụng
Sử dụng ransack cùng với dữ liệu mẫu products
Trong controller
Tìm kiếm đối tượng bằng cách sử dụng Product.search với tham số:q là một hash bao gồm các cột trong products model mà bạn muốn tìm kiếm products theo nó, gọi hàm result để trả về kết quả result để trả về kết quả.
app/controller/products_controller.rb
class ProductsController < ApplicationController
def index
@search = Product.search(params[:q])
@products = @search.result
end
end
Trong view
Sử dụng search_form_for thay cho form_for, @search để lấy dữ liệu
app/views/products/index.html.erb
<%= search_form_for @search do |f| %>
<div class="field">
<%= f.label :name_cont, "Name contains" %>
<%= f.text_field :name_cont %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Nhập bất kì thông tin bạn muốn tìm kiếm, ransack sẽ trả về kết quả cho bạn
Ngoài ra, có thể thêm nhiều option tìm kiếm, ví dụ theo khoảng giá của products
<%= search_form_for @search do |f| %>
<div class="field">
<%= f.label :name_cont, "Name contains" %>
<%= f.text_field :name_cont %>
</div>
<div class="field">
<%= f.label :price_gteq, "Price between" %>
<%= f.text_field :price_gteq %>
<%= f.label :price_lteq, "and" %>
<%= f.text_field :price_lteq %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Giống như trong hệ quản trị cơ sở dữ liệu sql, ransack cho phép bạn sắp xếp kết quả tìm kiếm theo tên trường bằng cách click vào tên tiêu đề trường.
app/views/products/index.html.erb
<tr>
<th><%= sort_link(@search, :name, "Product Name") %></th>
<th><%= sort_link(@search, :released_on, "Release Date") %></th>
<th><%= sort_link(@search, :price, "Price") %></th>
</tr>
Tìm kiếm động
Ransack còn cung cấp cho người dùng khả năng tìm kiếm động, cho phép select các trường mà họ muốn tìm kiếm, sử dụng condition_fields method để làm điều này app/views/products/index.html.erb
<%= search_form_for @search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select %>
<% end %>
<%= c.predicate_select %>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Đồng thời trong controller tương ứng, thêm @searchbuild_condition để thực hiện tìm kiếm động
Kết quả
Ransack còn cho phép bạn tìm kiếm kết hợp dựa trên has_many, belongs_to. app/views/products/index.html.erb
<%= a.attribute_select associations: [:category] %>
Thêm xóa các điều kiện tìm kiếm
Tạo partial form, add link remove search
app/views/products/_condition_fields.html.erb
<div class="field">
<%= f.attribute_fields do |a| %>
<%= a.attribute_select associations: [:category] %>
<% end %>
<%= f.predicate_select %>
<%= f.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
<%= link_to "remove", '#', class: "remove_fields" %>
</div>
Viết hàm link_to_add_fields trong ApplicationHelper. app/helper/application_helper.rb
module ApplicationHelper
def link_to_add_fields(name, f, type)
new_object = f.object.send "build_#{type}"
id = "new_#{type}"
fields = f.send("#{type}_fields", new_object, child_index: id) do |builder|
render(type.to_s + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
thêm add, remove link vào indexhtml.erb
<%= search_form_for @search do |f| %>
<%= f.condition_fields do |c| %>
<%= render "condition_fields", f: c%>
<% end %>
<p><%= link_to_add_fields "Add Conditions", f, :condition %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Sử dụng đoạn javascript để thực hiện thêm, xóa link trong index views app/assets/javascript/products.jscoffee
jQuery ->
$('form').on 'click', '.remove_fields', (event) ->
$(this).closest('.field').remove()
event.preventDefault()
$('form').on 'click', '.add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
Khi có quá nhiều condition được dùng để search, dữ liệu truyền trên get requset bị giới hạn, vì vậy ,thay vì sử dụng get request ta sử dụng pót request , add search routes, action index trong routes.
config/routesrb
Store::Application.routes.draw do
resources :products do
collection { post :search, to: 'products#index' }
end
root to: 'products#index'
end
Thêm url, post method trong form search
<%= search_form_for @search, url: search_products_path, method: :post do |f| %>
<%= f.condition_fields do |c| %>
<%= render "condition_fields", f: c %>
<% end %>
<p><%= link_to_add_fields "Add Conditions", f, :condition %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Một số tính năng nâng cao khác
Ransack còn cung cấp cho người dùng môt số tính năng nâng cao khác như
- Authorization, dựa trên whitelist, blacklist
Người dùng chỉ có thể searching, sorting trên một số cột nhật định trong whitelists.
- Sử dụng or thay vì and
Mặc định của việc tìm kiếm trên nhiều trường trong ransack là and, thay vì vậy bạn có thể sử dụng or, thay đổi diều này trong params[:q].
Kết luận
Ransack là một công cụ tìm kiếm tuyệt, rất đơn giản, dễ sử dụng và hiệu quả. Tuy nhiên vẫn có những hạn chế nhất đinh như việc chưa thể phân trang với kết quả tìm kiếm mà phải thực hiện bằng javascript.
All rights reserved