Rails搜索多个条件(如果值不为空)

时间:2012-02-16 09:42:15

标签: ruby-on-rails activerecord

假设我有一个带有字段Book的模型word_count,可能还有很多其他类似的字段。

对我来说,在数据库的“高级搜索”中将条件串起来有什么好方法?在上面的例子中,我有一个带有“word count between ___ and ___”框的搜索表单。如果用户填写第一个框,那么我想要返回字数大于该值的所有图书;同样,如果用户填写第二个框,那么我想要返回字数少于该值的所有书籍。如果两个值都被填入,那么我想返回该范围内的字数。

显然,如果我这样做

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

如果只填写其中一个字段,则会中断。有没有办法优雅地处理这个问题?请记住,可能存在许多类似的搜索条件,因此我不想为每种可能的组合构建单独的查询。

很抱歉,如果之前已经提出此问题,但搜索网站尚未产生任何有用的结果。

3 个答案:

答案 0 :(得分: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]&amp;&amp;值[1]如果值[0]大于值[1],查询将不返回任何内容。

答案 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)

答案 2 :(得分:0)

看一下ransack gem,它是meta_search gem的继承者,它似乎仍然有更好的文档。

如果您确实想要自己推送,那么没有什么能阻止您使用相同的属性来链接子句:

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

但是真的没有必要推出自己的搜索,有很多现成的解决方案,如上面的宝石。