我要求允许接口根据一组冗长的过滤选项(价格,平台,可用性等)缩小产品表。
过滤器必须复合,以便访问者可以先按价格排序,然后将平台搜索过滤器添加到现有价格过滤器。过滤器也必须是可拆卸的。
此外,结果需要有多个排序选项以及分页。
有关实施此类内容的最佳方法的任何建议吗?
我正在研究has_scope
,我们也将使用Solr / Sunspot进行搜索,但我们愿意接受任何建议。
答案 0 :(得分:1)
这是一个简单的方法,下面是一个更简洁的版本,但第二个更难理解而没有第一个......
鉴于您的过滤条件为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
。最后,您的products实例变量将保存已过滤的集合。这是有效的,因为ActiveRecord类上的#where方法是chainable
,每次返回一个Relation
对象,您可以在其中应用另一个#where。
第一个.where(true)片段有点hacky,但是如果你没有把它放进去,那么当所有过滤器都是nil时,@ product将是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?})
这是有效的,因为您可以将entire hash
条件传递给#where方法。 #where调用中的params.select
部分代码会从params
哈希中提取所有键值对,其中键与您的某个过滤条件and
匹配,值为non-nil
},并将生成的哈希提供给#where。这似乎也没有上面提到的all-filters-nil issue
,因为当所有都为零时,#where获得一个空哈希并选择全部。
答案 1 :(得分:0)
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,它可以保存在会话中,或者(我认为更好,因为它允许书签和后退按钮)作为URL的一部分。您可以在控制器的索引操作中按顺序应用每个过滤器元素。
答案 2 :(得分:0)
我最终了解了Solr / Sunspot方面,并将其应用于搜索条件。