6

我正在實現一個簡單的搜索函數,該函數應該檢查用戶名,姓氏和名字中的字符串。我已經看到了這個ActiveRecord的方法在一箇舊RailsCast:Rails ActiveRecord - 在多個屬性上搜索

http://railscasts.com/episodes/37-simple-search-form

find(:all, :conditions => ['name LIKE ?', "%#{search}%"]) 

但我怎麼讓這個它搜索的名字,姓氏和名字的關鍵字,並返回如果記錄其中一個字段與該術語相匹配?

我也想知道RailsCast上的代碼是否容易出現SQL注入?

非常感謝!

回答

20

我假定你的型號是Model - 只是你的真實模型名稱替換它,當你這樣做的實際查詢:

Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#{search}%","%#{search}%","%#{search}%") 

關於您的後顧之憂有關SQL注入 - 兩者的代碼片段是免疫的SQL注入。只要你不直接在你的WHERE子句中嵌入字符串,你很好。注射易發生代碼的一個例子是:

Model.where("name LIKE '#{params[:name]}'") 
+0

正是我需要的。感謝您解釋清楚! – maru 2012-08-05 14:00:45

+0

如果控制器更改爲傳遞整個'params'而不是'params [:search]',並且在我們的查詢中我們使用'「%#{params [:search]}%」'而不是'「%## {}搜索%「'。這仍然不受SQL注入的影響嗎? – Dennis 2014-02-04 19:24:06

+0

@丹尼斯是的。只要你使用?並傳遞額外的參數在查詢中替換它們,你很好。 – 2014-02-06 05:40:53

8

雖然選擇的答案會的工作,我注意到,它打破,如果您嘗試鍵入搜索「勞爾裏埃拉」,因爲它會在兩種情況下會失敗,因爲勞爾裏埃拉不是非此即彼我的名字或我的姓..是我第一次和最後一個名字......我解決它做

Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%") 
+0

我發現這個答案更有用。謝謝! – 2015-09-09 05:32:43

+0

使用'ILIKE'而不是使用小寫不是更好嗎?讓DB處理它。 – 2017-06-17 13:45:04

+0

當last_name或first_name等於nil時它不起作用,如果需要,則需要將默認空字符串值設置爲名和姓 – 2017-10-06 13:18:25

0

最好的方式做到這一點是:

Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%") 
0

隨着Arel,你可以避免寫作SQL手動執行如下操作:

Model.where(
    %i(name first_name last_name) 
    .map { |field| Model.arel_table[field].matches("%#{query}%") 
    .inject(:or) 
) 

如果匹配的字段列表是動態的,這將特別有用。