Rails 簡易搜尋功能


如果有長期關注的朋友,會覺得我怎麼現在改寫網站設計和網站工程的內容了。不要懷疑,我目前都在玩Ruby on Rails,所以也會寫相關文章,請大家多多指教。

今日分享功能:從資料庫中搜尋所有含特定字串的項目
Ruby版本:2.1.2
Rails版本:4.1.0
系統:MAC OSX 10.9.4

今天要分享的是一個Rails非常簡單的搜尋功能,比我想像中的簡單了大概一百倍。可能我原本以為要搞到像Google那樣才算是搜尋,但其實可以弄得很簡單。Railcast裡面也有非常詳盡的說明。

前提

  1. 安裝Ruby、Rails環境
  2. 已建立一個Rails程式,帶有app/views/index.html.erb頁面
  3. 有一個model叫做Product,帶有title、description (資料庫中已有數筆資料)
  4. 有一個controller包含了index action

搜尋的唯一重點就在於從view回傳一個變數 :search 回controller,剩下的就都交給Rails自建的ActiveRecord指令就好。

1. 建立搜尋表格

首先,到view當中建立一個 form_tag ,直接開始建立搜尋欄位

<%= form_tag products_path, method: :get do %>
    <%= text_field_tag :search, params[:search], placeholder: "Search..." %>
<% end %>

在畫面中,就會出現一個搜尋框,簡單說明一下:

  1. form_tag 使用的 method 方法不一,這邊要限定為method: :get,才能確實抓資料。
  2. 連結部分設定回index頁面,也可以設定為其他自訂的搜尋頁
  3. params[:search]的使用,會回傳一個search的變數,也就是網址列的後方會出現?utf8=✓&search=search的字樣
  4. placeholder是搜尋框內的預設文字,只要使用者輸入任何文字,這段預設文字就會消失

如果你比較喜歡要有『搜尋』這個按鈕,那可以設定為下方的樣式:

<%= form_tag admin_products_path, method: :get do %>
    <%= text_field_tag :search, params[:search], placeholder: "Enter Text..." %>
    <%= submit_tag "Search", name: nil %>
<% end %>

唯一有一點需要解釋的是search這顆按鈕按下去以後會預設傳送出commit=search變數到網址列裡頭,沒有意義,所以多設定了 name: nil的部份,讓他不會傳送任何其他多餘的資訊出去。

2. 建立搜尋功能

主頁面設定好以後,接下來到controller裡面進行調整:

class ProductsController < ApplicationController
    def index
        if params[:search]
            @product = Product.where('title LIKE ?', "%#{params[:search]}%")
        else
            @product = Product.all
        end
    end
end

這個地方分成兩個區塊,邏輯是:『如果有搜尋,就把搜尋結果列出來;如果沒有進行搜尋,就把所有產品都列出來。』

  1. where就是Rails內建用來比對資料使用
  2. 'title LIKE ?'代表product底下的title欄位是否帶有特定字串
  3. "%#{params[:search]}%"代表我們將剛剛在view中送出的params[:search]變數傳送到這裡來進行搜尋。#{}符號是將變數正確使用於""符號內,而前後兩個%%符號代表要進行模糊比對而非精確比對,如果是直接填入params[:search]就會進行精確比對。

這樣就可以在搜尋時,讓結果頁面列出所有標題包含特定字串的model項目。到這邊就算是設定完成囉,舉國歡騰!

3. 進行多個欄位搜尋

這邊開始是RailsCast沒有講的部分,同樣分享給大家。

剛剛設定的搜尋功能,僅限於搜尋一個欄位,也就是如果要搜尋產品,就只能搜尋title欄位。假如我需要同時搜尋title和description兩個欄位呢?身為一個搜尋功能,要搜尋所有文字資料也是很合理的。

因此,我們可以將controller的搜尋內容修改如下:

class ProductsController < ApplicationController
  def index
        if params[:search]
                @product = Product.where('title LIKE ? OR description LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%")
        else
                @product = Product.all
        end
  end
end

看到哪裡不同了嗎?在where後方跟著的句法,變得有點長,因為我們設定了同時搜尋title和description兩個項目,中間加了一個OR,代表只要有一個地方符合,就會出現在搜尋結果中,而後方一次重複的"%#{params[:search]}%"則是因為針對description進行了同樣的搜尋,所以在後方也重複出現。

希望大家都設定成功喔!

(圖片來源:Sean MacEntee)