2012-02-16 52 views
1

比方說,我有一個模型Book,其中有一個字段word_count,可能還有許多其他類似的字段。用多種條件搜索導軌(如果值不爲空)

對我來說,在數據庫的「高級搜索」中將條件串在一起的好方法是什麼?在上面的例子中,我會爲「word count between ___ and ___」提供包含框的搜索表單。如果用戶填寫第一個框,那麼我想返回所有字數大於該值的書;同樣,如果用戶填寫第二個框,那麼我想返回所有字數小於該值的書籍。如果兩個值都填入,那麼我想返回該範圍內的字數。

顯然,如果我不

Book.where(:word_count => <first value>..<second value>) 

,那麼這將打破,如果只有其中一個字段中瀰漫。有什麼辦法能夠完美地處理這個問題?請記住,可能有許多類似的搜索條件,所以我不想爲每個可能的組合建立單獨的查詢。

對不起,如果這個問題之前已經問過,但搜索網站還沒有產生任何有用的結果呢。

回答

0

看看ransack寶石,它是meta_search寶石的繼承者,它仍然看起來有更好的文檔。

如果你想推出自己的,沒有什麼原因導致您無法使用相同的屬性鏈接條款:

scope = Book 
scope = scope.where("word_count >= ?", params[:first]) if params[:first] 
scope = scope.where("word_count <= ?", params[:last]) if params[:last] 

但它確實沒有必要推出自己的搜索,有很多現成的解決方案可用就像上面的寶石一樣。

1

如何像:

@books = Book 
@books = @books.where("word_count >= ?", values[0]) if values[0].present? 
@books = @books.where("word_count <= ?", values[1]) if values[1].present? 

的ActiveRecord將鏈中的where子句

唯一的問題是,如果值[0] & &值[1]的查詢將不會返回,如果值什麼[0]大於值[1]。

1

對於我們的高級搜索,我們創建了一個過濾器對象,它將activerecord查詢封裝到簡單的方法中。它最初是在此基礎上Thoughtbot post

書過濾器可以是這個樣子:

class BookFilter 
    def initialize 
    @relation = Book.scoped 
    end 

    def restrict(r) 
    minimum_word_count!(r[:first]) if r[:first].present? 
    maximum_word_count!(r[:second]) if r[:second].present? 
    recent! if r.try(:[], :recent) == '1' 
    @relation 
    end 

    protected 

    def recent! 
    where('created_at > ? ', 1.week.ago) 
    end 

    def minimum_word_count!(count) 
    where('word_count >= ? ', count) 
    end 

    def maximum_word_count!(count) 
    where('word_count <= ?', count) 
    end 

    def where(*a) 
    @relation = @relation.where(*a) 
    end 
end 

#to use 
books = BookFilter.new.restrict(params) 
+0

我挺喜歡這是怎麼回事。不過,我在哪裏上課? – 2012-02-17 10:29:18

+0

我們把它們放到'app/models'中。您可以將它們命名爲'Filters',並將它們放在'lib/filters'文件夾中 – roo 2012-02-17 12:46:56