2011-03-11 51 views
2

我試圖用Ruby,ActiveRecord和MySQL在報價數據庫中搜索多個詞。我做的方式如下所示,它正在工作,但我想知道是否有更好的方法。用Ruby和MySQL搜索多個詞

# receives a string, splits it in a array of words, create the 'conditions' 
# query, and send it to ActiveRecord 
def search 
    query = params[:query].strip.split if params[:query] 
    like = "quote LIKE " 
    conditions = "" 
    query.each do |word| 
     conditions += (like + "'%#{word}%'") 
     conditions += " AND " unless query.last == word 
    end 
    @quotes = Quote.all(:conditions => conditions) 
end 

我想知道是否有更好的方法來編寫這個'條件'字符串。我也嘗試過使用字符串插值,例如使用*運算符,但最終需要更多的字符串處理。在此先感謝

回答

7

首先,我強烈建議您將Model的邏輯轉換爲Models。不要在Controller中創建搜索邏輯,而要在報價模式中創建#search方法。

class Quote 
    def self.search(query) 
    ... 
    end 
end 

和您的控制器將成爲

# receives a string, splits it in a array of words, create the 'conditions' 
# query, and send it to ActiveRecord 
def search 
    @quotes = Quote.search(params[:query]) 
end 

現在,回到原來的問題。您現有的搜索邏輯確實犯了一個非常糟糕的錯誤:它直接插值打開您的代碼到SQL注入。假設你使用Rails 3,你可以利用新的#where語法。

class Quote 
    def self.search(query) 
    words = query.to_s.strip.split 
    words.inject(scoped) do |combined_scope, word| 
     combined_scope.where("quote LIKE ?", "%#{word}%") 
    end 
    end 
end 

這是一個高級話題。我想了解combined_scope + inject做什麼,我建議您閱讀文章The Skinny on Scopes

+0

如果您在示例中演示了mysql的全文搜索 – 2011-03-11 19:56:47

+2

,我會推薦'to_s.downcase.strip.split.uniq'將其摺疊爲小寫並刪除重複的單詞。 – 2011-03-12 05:17:29

+0

我正在使用Rails 2.3.5,但無論如何,答案有很大幫助。謝謝。 – Eduardo 2011-03-12 14:37:48

1

更好的方法來執行全文搜索。您可以在MySQL中這樣做,但我會強烈建議Solr。有許多資源online用於在軌道中實施Solr,但我會推薦Sunspot作爲入口點。

+0

Solr的確實是一個不錯的選擇,但它是一個相當複雜的庫。在某些情況下,您實際上並不需要添加Solr依賴關係,對MySQL嘗試這種查詢是完全正確的。我相信在這種情況下,用戶可以通過重構他的代碼而獲得高度益處,而無需採取步驟來嘗試Solr。 – 2011-03-11 17:11:43

3

MySQL的全文檢索不能正常工作,那麼最好的方式做到這一點:

class Quote 
    def self.search_by_quote(query) 
    words = query.to_s.strip.split 
    words.map! { |word| "quote LIKE '%#{word}%'" } 
    sql = words.join(" AND ") 
    self.where(sql) 
    end 
end