Tìm hiểu về Ransack Gem và ứng dụng trong tìm kiếm
I.Tổng quan Ransack là một gem được viết lại từ gem MetaSearch được dùng để tìm kiếm dữ liệu. Nó hỗ trợ nhiều tính năng tương tự như MetaSearch nhưng khác nhau khá nhiều so với MetaSearch trong cách thức thực hiện tìm kiếm, và tính tương thích không phải là mục tiêu thiết kế của nó. Ransack ...
I.Tổng quan
Ransack là một gem được viết lại từ gem MetaSearch được dùng để tìm kiếm dữ liệu. Nó hỗ trợ nhiều tính năng tương tự như MetaSearch nhưng khác nhau khá nhiều so với MetaSearch trong cách thức thực hiện tìm kiếm, và tính tương thích không phải là mục tiêu thiết kế của nó.
Ransack cho phép tạo ra cả hai hình thức tìm kiếm đơn giản và tìm kiếm nâng cao tùy theo các mô hình ứng dụng trong chương trình.
II.Sử dụng Ransack (Getting started)
1. Cài đặt
Ransack khả dụng với Rails 3.x, 4.0, 4.1 và 4.2.
Thêm dòng sau vào Gemfile:
gem "ransack”
Hoặc nếu bạn muốn dùng bản mới nhất của Ransack:
gem "ransack", :git => "git://github.com/ernie/ransack.git"
2. Cách sử dụng (Usage)
Ransack có thể được sử dụng theo một trong hai chế độ, đơn giản hoặc nâng cao.
2.1. Simple Mode (Mô hình đơn giản)
Mô hình này hoạt động giống như Meta Search, với những người đã quen thuộc với nó thì đòi hỏi những thiết lập rất nhỏ.
Nếu đã biết Meta Search, những điều cần lưu ý :
-
Từ khóa mặc định cho param tìm kiếm bây giờ là :q, thay vì :search. Mục đích là để rút ngắn chuỗi truy vấn query strings trên trình duyệt.
-
form_for chuyển thành search_form_for, và xác nhận (chắc chắn) rằng một Ransack::Search object được truyền cho nó.
-
Các method Common ActiveRecord::Relation không còn được phân cấp bởi các đối tượng tìm kiếm như trước. Thay vào đó, bạn sẽ nhận được kết quả tìm kiếm thông qua việc gọi Search#result.
-
Nếu được thông qua (distinct: true), result sẽ tạo ra một truy vấn SELECT DISTINCT để tránh trả về các bản ghi trùng lặp ngay cả khi các điều kiện trong 1 join sẽ không dẫn đến trùng lặp.
Lưu ý đối với nhiều cơ sở dữ liệu, distinct: true không khả dụng. Trong trường hợp đó sử dụng #to_a.uniq với tập kết quả để lấy được các bản ghi duy nhất.
Controller:
def index @q = Person.search(params[:q]) @people = @q.result(distinct: true) end //hoặc def index @q = Person.search(params[:q]) @people = @q.result.includes(:articles).page(params[:page]) # hoặc sử dụng `to_a.uniq` để xóa các bản ghi trùng lặp như dưới đây (có thể dùng cả trong view): @people = @q.result.includes(:articles).page(params[:page]).to_a.uniq end
View:
Sử dụng search_form_for thay vì form_for để tạo form search trong view :
<%= search_form_for @q do |f| %> # Tìm kiếm theo tên ... <%= f.label :name_cont %> <%= f.text_field :name_cont %> # Search if an associated articles.title starts with... <%= f.label :articles_title_start %> <%= f.text_field :articles_title_start %> # Tìm kiếm theo nhiều attr cho 1 giá trị ... <%= f.label :name_or_description_or_email_or_articles_title_cont %> <%= f.text_field :name_or_description_or_email_or_articles_title_cont %> <%= f.submit %> <% end %>
cont (contains) và start (starts with) là 2 phương thức tìm kiếm mặc định trong ransack.Xem thêm thông tin có thể vào Constants hoặc wiki.
Advanced Mode
Tìm kiếm Advanced sử dụng thuộc tính lồng nhau của Rails để tạo ra các truy vấn phức tạp với nhiều model khác nhau trong ứng dụng.
Thiết lập Routes:
resources :people do collection do match 'search' => 'people#search', :via => [:get, :post], :as => :search end end
… thêm action trong controller …
def search index render :index end
… cập nhật search_form_for trong view …
<%= search_form_for @q, :url => search_people_path, :html => {:method => :post} do |f| %>
Ransack #search method
Ransack sẽ tạo #search phù hợp trong model, trong trường hợp #search đã được định nghĩa thì có thể sử dụng #ransack. Ví dụ :
Article.search(params[:q]) Article.ransack(params[:q])
Associations
Có thể dễ dàng sử dụng Ransack để tìm kiếm các object liên kết với nhau bằng quan hệ has_many và belongs_to. Giả sử có mối liên kết như sau:
class Employee < ActiveRecord::Base belongs_to :supervisor end class Department < ActiveRecord::Base has_many :supervisors end class Supervisor < ActiveRecord::Base belongs_to :department has_many :employees end
… và controller
class SupervisorsController < ApplicationController def index @search = Supervisor.search(params[:q]) @supervisors = @search.result(:distinct => true) end end
… form view được thiết lập
<%= search_form_for @search do |f| %> <%= f.label :last_name_cont %> <%= f.text_field :last_name_cont %> <%= f.label :department_title_cont %> <%= f.text_field :department_title_cont %> <%= f.label :employees_first_name_or_employees_last_name_cont %> <%= f.text_field :employees_first_name_or_employees_last_name_cont %> <%= f.submit "search" %> <% end %> ... <%= content_tag :table %> <%= content_tag :th, sort_link(@q, :last_name) %> <%= content_tag :th, sort_link(@q, "departments.title") %> <%= content_tag :th, sort_link(@q, "employees.last_name") %> <% end %>
Using Scopes/Class Methods
Tìm bởi scope yêu cầu định nghĩa 1 whitelist của ransackable_scopes trong model class, whitelist nên là 1 mảng các ký tự. Mặc định tất cả các class method được bỏ qua,. Scope sẽ applied cho matching các giá trị true hoặc các giá trị mà scope chấp nhận :
class Employee < ActiveRecord::Base scope :active, ->(boolean = true){(where active: boolean)} scope :salary_gt, ->(amount){where('salary > ?', amount)} # Scopes are just syntactical sugar for class methods, which may also be used: def self.hired_since(date) where('start_date >= ?', date) end private def self.ransackable_scopes(auth_object = nil) if auth_object.try(:admin?) # allow admin users access to all three methods %i(active hired_since salary_gt) else # allow other users to search on active and hired_since only %i(active hired_since) end end end Employee.search({active: true, hired_since: '2013-01-01'}) Employee.search({salary_gt: 100_000 }, { auth_object: current_user})
3. Lời kết
Link trên github : https://github.com/nguyenhoa/brs_2/commit/aa71c0c3ba4f375b57510c2ad50fa3208e26d947
Link trên heroku : http://brs2.herokuapp.com/
admin account : admin1@example.com
user account : user1@example.com
password : foobar
Chỉ dẫn : đăng nhập -> View -> Users (search form trong users index)
Nguồn tham khảo:
https://github.com/ernie/ransack
https://github.com/railscasts/370-ransack
http://railscasts.com/episodes/370-ransack?autoplay=true