Nic Lin's Blog

喜歡在地上滾的工程師

[Rails] 用 Ransack 做搜尋功能

常見的情境有,搜索用戶資料、搜尋文章等等

而在 Rails 裡面有一個做基礎搜尋功能的 gem 他叫 Ransack,之所以會說只能做基本搜尋是因為,他是在下搜尋關鍵字的時候,從 database 裡面做模糊搜索,使用 like 去做 query

例如我們要搜尋 User 的 first name,名叫 Nic 的資料

在 ransack 裡面的寫法是

User.ransack(first_name_cont: 'Nic')

而他轉成 SQL 就會變成

SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Nic%')

除了「模糊搜索」以外,需要更精準的搜索就需要用到「全文搜索」了

這部份就可以參考全文搜索的引擎(需要額外架設)

  • solr
  • elasticsearch

不過這篇就只說使用 ransack 在 Rails App 裡面實作搜尋吧

設計目標

  • 單獨的 Search Controller
  • 漂亮的路徑 example.com/search?#{search_key_word}

安裝 ransack

gem 'ransack'

設定 controller 與 routes

創建 search controller

rails g controller search

get "/search" => "search#index", :as => "search"

接下來我們要處理透過 form 送進來的 params,濾掉一些不必要的字符,這部份可以在 controller 裡面做 validation

def validate_search_key
  @query_string = params[:q].gsub(/\\|\'|\/|\?/, "") if params[:q].present?

  @search_criteria = search_criteria(@query_string)
end

然後告訴 controller 我們要搜尋的範圍

def search_criteria(query_string)
  { :title_or_description_cont => query_string } 
end

title_or_description_cont 是ransack提供的方法 意思是說,搜尋這個 model 裡面的 title 或是 description 欄位

接下來我們完成 index action

def index
  if @query_string.present?
    @search = Topic.search(@search_criteria).result(:distinct => true)  
  end
end

接下來只要將其搜尋結果,用 view 呈現出來,搜尋功能就完成了。

在這邊我們看到的 web url 會是

http://example.com/search?utf8=✓&q=test

其中的 q=test 就是我們從 form 送進去的搜尋內容

utf8=✓ 則是為了符合古老的瀏覽器 ie6, Rails 在 form 裡面幫我們自帶的 attribute

附上最後拼湊完成的 Search Controller

class SearchController < ApplicationController
  before_action :validate_search_key

  def index
    if @query_string.present?
      @search = Topic.search(@search_criteria).result(:distinct => true)  
    end
  end
  
  protected
  
  def validate_search_key
    @query_string = params[:q].gsub(/\\|\'|\/|\?/, "") if params[:q].present?
    @search_criteria = search_criteria(@query_string)
  end

  def search_criteria(query_string)
    { :title_or_content_cont => query_string }
  end

end
comments powered by Disqus