Viblo CTF
+7

Tìm hiểu Gem Ransack

I. Ransack là gì?

  • Ransack là 1 gem trong Ruby on the Rails giúp hỗ trợ người dùng xây dựng các tìm kiếm.
  • Ransack cho phép tìm kiếm với hai hình thức đơn giản và nâng cao tùy theo các mô hình ứng dụng trong chương trình.
  • Ngoài ra, nó còn giúp sắp xếp kết quả tìm kiếm được theo mục đích của người sử dụng.

II. Cài đặt

Thêm gem ransack vào Gemfile, sau đó bundle.


gem 'ransack'

III. Ví dụ

  • Áp dụng với dữ liệu mẫu User với các trường: name, age Screenshot from 2015-06-26 10:36:45.png

  • Để tìm kiếm các users thì sau khi cài đặt gem ransack xong, trong user_controller.rb ta sử dụng User.search với param mặc định là params[:q], với tham số q là một hash gồm các trường của User và cách tìm kiếm trường đó. Để lấy kết quả tìm kiếm ta sử dụng hàm result.


class UsersController < ApplicationController
  def index
    @search = User.search(params[:q])
    @users = @search.result
  end
end
  • Trong view Ransack sử dụng search_form_for thay vì form_for bình thường để tạo form search cho @search:

<%= search_form_for @search, class: "form-inline" do |f| %>
	<div class="form-group">
    	<%= f.label :name_cont, 'User Name:' %>
        <%= f.text_field :name_cont, class: "form-control" %><br>
    </div> <!-- Tìm kiếm theo name có chứa ... -->
    <div class="form-group">
        <%= f.label :age_gteq, 'Age >= ' %>
        <%= f.text_field :age_gteq, class: "form-control" %><br>
    </div> <!-- Tìm kiếm theo age lớn hơn bằng ...  -->
    <%= f.submit 'Search', class: "btn btn-default" %>
<% end %>

_Tìm kiếm các user có name chứa "Nguyen" _

Screenshot from 2015-06-26 10:52:20.png

_... và age lớn hơn bằng 25 _

Screenshot from 2015-06-26 10:52:32.png

Ta cũng có thể tìm kiếm nhiều trường một lúc:


	<div class="form-group">
        <%= f.label :name_or_nick_name_cont, 'Name or Nick Name:' %>
        <%= f.text_field :name_or_nick_name_cont, class: "form-control" %><br>
    </div>

Screenshot from 2015-06-26 11:12:41.png

  • Một số quy tắc search:
  1. eq (equals): bằng

     VD:
    

        User.ransack(name_eq: 'Hang').result.to_sql
	    => SELECT "users".* FROM "users" WHERE "users"."name" = 'Hang'
  1. not_eq: không bằng, ngược lại với eq

  2. lt(less than): ít hơn

     VD:
    

        User.ransack(age_lt: 25).result.to_sql
    => SELECT "users".* FROM "users" WHERE ("users"."age" < 25)
  1. gt(greater than): lớn hơn, ngược lại với lt

  2. lteq (less than or equal to): ít hơn hoặc bằng

     VD:
    

        User.ransack(age_lteq: 25).result.to_sql
    => SELECT "users".* FROM "users" WHERE ("users"."age" <= 25)
  1. gteq (greater than or equal to) : lớn hơn hoặc bằng, ngược lại với lteq

  2. in: nằm trong ...

     VD:
    

        User.ransack(age_in: 20..22).result.to_sql
    => SELECT "users".* FROM "users" WHERE "users"."age" IN (20, 21, 22)
  1. not_in: không nằm trong..., ngược lại với in

  2. cont: chứa ...

     VD:
    

        User.ransack(nick_name_cont: 'Hon').result.to_sql
    => SELECT "users".* FROM "users"  WHERE ("users"."nick_name" LIKE '%Hon%')
  1. not_cont: không chứa..., ngược lại với cont

  2. end (ends with): kết thúc bằng...

    VD:
    

        User.ransack(nick_name_end: 'Hon').result.to_sql
    => SELECT "users".* FROM "users"  WHERE ("users"."nick_name" LIKE '%Hon')
  1. not_end: không kết thúc bằng..., ngược lại với end

  2. start (starts with): bắt đầu bằng...

    VD:
    

        User.ransack(nick_name_start: 'Hon').result.to_sql
    => SELECT "users".* FROM "users"  WHERE ("users"."nick_name" LIKE 'Hon%')
  1. not_start: không bắt đầu bằng..., ngược lại với start

    ...

  • Ransack cung cấp cách sort các kết quả search được theo link:

Trong view index.html.erb:


<tr>
    <th><%= sort_link(@search, :name, 'User Name') %></th>
    <th><%= sort_link(@search, :age, 'Age') %></th>
</tr>

Khi tải lại trang sẽ có các liên kết để phân loại các bảng kết quả theo từng trường.

Sắp xếp age theo thứ tự giảm dần

Screenshot from 2015-06-26 13:09:01.png

  • Ransack hỗ trợ tự động tìm kiếm theo nhu cầu: tự chọn trường, cách thức tìm kiếm, giá trị:

Trong user_controller.rb thêm:


	...
	@search.build_condition

Trong view index.html.erb sử dụng condition_fields method:


<%= search_form_for @search, class: "form-inline" do |f| %>
    <%= f.condition_fields do |c| %>
        <%= c.attribute_fields do |a| %>
            <%= a.attribute_select %>
        <% end %>
        <%= c.predicate_select %>
        <%= c.value_fields do |v| %>
            <%= v.text_field :value %>
        <% end %>
      <% end %>
      <%= f.submit 'Search', class: "btn btn-default" %>
    <% end %>
<% end %>
  • Tương tự như vậy, ransack cũng áp dụng tùy chọn với sort:

Trong user_controller.rb thêm:


	...
	@search.build_sort

Trong view index.html.erb sử dụng sort_fields method:


<%= f.sort_fields do |s| %>
    <%= s.sort_select %>
<% end %>

Minh họa

Screenshot from 2015-06-26 14:16:44.png

  • Ngoài ra nếu truyền quá nhiều dữ liệu tìm kiếm mà trên GET request bị giới hạn ta có thể thay thế bằng POST request:

Trong config/routes.rb


Rails.application.routes.draw do
  root to: 'users#index'
  resources :users do
    collection { post :search, to: 'users#index' }
  end
end

search_form_for:


<%= search_form_for @search, url: search_users_path, method: :post do |f| %>
	...
<% end %>

Kết luận: Ransack thực sự là một công cụ hỗ trợ tìm kiếm đơn giản và dễ dàng trong thư viện gem của Ruby on the Rails.

Tài liệu tham khảo:

http://railscasts.com/episodes/370-ransack?view=asciicast

https://github.com/activerecord-hackery/ransack


All Rights Reserved