我有一個要求,允許界面根據一組冗長的過濾選項(價格,平臺,可用性等)縮小產品表。如何在表上構建多個屬性過濾?
過濾器必須複合,以便訪問者可以先按價格排序,然後將平臺搜索過濾器添加到現有的價格過濾器。過濾器也必須是可移動的。
此外,結果將需要有幾個排序選項以及分頁。
有關實現這樣的最佳方式的任何建議嗎?
我正在調查has_scope
,我們也將使用Solr /太陽黑子進行搜索,但我願意接受任何建議。
我有一個要求,允許界面根據一組冗長的過濾選項(價格,平臺,可用性等)縮小產品表。如何在表上構建多個屬性過濾?
過濾器必須複合,以便訪問者可以先按價格排序,然後將平臺搜索過濾器添加到現有的價格過濾器。過濾器也必須是可移動的。
此外,結果將需要有幾個排序選項以及分頁。
有關實現這樣的最佳方式的任何建議嗎?
我正在調查has_scope
,我們也將使用Solr /太陽黑子進行搜索,但我願意接受任何建議。
我最終學習了Solr /太陽黑子方面並將其應用於搜索條件。
Rails 3 ActiveRecord有一個很好的機制來處理像這樣的東西。你可以在你的ActiveRecord上調用方法如where
或order
,你得到的回報將是Relation
。然後可以調用該對象的其他方法來進一步縮小搜索邊界或指定連接等。只有在對象實際上將數據從數據庫傳遞迴Ruby的方法上調用數據庫時,數據庫纔會實際上被擊中。更多細節在這裏:
http://m.onkey.org/active-record-query-interface
http://railscasts.com/episodes/202-active-record-queries-in-rails-3
從那裏,你只需要添加和刪除過濾元件的UI,它可以保存在session,或(我認爲更漂亮,因爲它允許書籤和後退按鈕)作爲URL的一部分。您可以在控制器的索引操作中按順序應用每個過濾器元素。
這是一個簡單的方法,下面是一個更簡潔的版本,但第二個是很難理解沒有第一...
鑑於您的篩選條件是price
,platform
和availability
...
適當地命名您的表單域,它們將作爲params hash
的一部分進入。然後,在你的控制器運行是這樣的:
@products = Product.where(true)
%w(price platform availability).each do |filter|
unless params[filter.to_sym].nil?
@products = @products.where(filter => params[filter.to_sym])
end
end
這將啓動對所有產品的佔位符,然後通過你的過濾步驟,並通過#where
與適當的條件適用各一個,除非該過濾器字段的值是nil
。最後,您的產品實例變量將保存已過濾的集合。這是有效的,因爲ActiveRecord類上的#where方法是chainable
,每次返回一個Relation
對象,您可以在其中應用另一個#where。
首先,凡真(true)件是有點冒險的,但如果你沒有把它放進去,那麼當所有過濾器都是零時,@products將是Product類對象而不是所有產品的集合。 #all方法已被棄用,所以我使用.where(true) - 不確定是否有更好或更可接受的方式來執行此操作。
請注意,在Rails 3中,除非您在集合上調用enumerable method
(例如#each
),否則實際上沒有任何操作針對數據庫執行,因此這應該對數據庫有效。
更簡潔的版本是這樣的......
@products = Product.where(params.select {|key, value| %w(price platform availability).include?(key.to_s) && !value.nil?})
這工作,因爲你可以在有條件的#WHERE方法的entire hash
通過。 #where調用中的params.select
部分代碼將從params
哈希中抽出所有鍵值對,其中鍵與您的篩選條件之一and
的值爲non-nil
,並將生成的哈希提供到#where中。這似乎也沒有上面提到的all-filters-nil issue
,因爲當所有的都是零時#shared獲得一個空的散列並且全選。
您使用的是哪個版本的Rails? – Yardboy
目前運行3.1.rc5 –