如何在表上构建多个属性过滤?

时间:2011-08-02 19:41:37

标签: ruby-on-rails ruby ruby-on-rails-3 filtering

我要求允许接口根据一组冗长的过滤选项(价格,平台,可用性等)缩小产品表。

过滤器必须复合,以便访问者可以先按价格排序,然后将平台搜索过滤器添加到现有价格过滤器。过滤器也必须是可拆卸的。

此外,结果需要有多个排序选项以及分页。

有关实施此类内容的最佳方法的任何建议吗?

我正在研究has_scope,我们也将使用Solr / Sunspot进行搜索,但我们愿意接受任何建议。

3 个答案:

答案 0 :(得分:1)

这是一个简单的方法,下面是一个更简洁的版本,但第二个更难理解而没有第一个......

鉴于您的过滤条件为priceplatformavailability ...

恰当地命名您的表单字段,它们将作为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上调用类似whereorder的方法,而您获得的内容将是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方面,并将其应用于搜索条件。