Rails searching with multiple conditions (if values are not empty)

妖精的绣舞 提交于 2019-12-13 19:27:43

问题


Let's say I have a model Book with a field word_count, amongst potentially many other similar fields.

What is a good way for me to string together conditions in an "advanced search" of the database? In the above example, I'd have a search form with boxes for "word count between ___ and ___". If a user fills in the first box, then I want to return all books with word count greater than that value; likewise, if the user fills in the second box, then I want to return all books with word count less than that value. If both values are filled in, then I want to return word counts within that range.

Obviously if I do

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

then this will break if only one of the fields was filled in. Is there any way to handle this problem elegantly? Keep in mind that there may be many similar search conditions, so I don't want to build separate queries for every possible combination.

Sorry if this question has been asked before, but searching the site hasn't yielded any useful results yet.


回答1:


How about something like:

@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 will chain the where clauses

The only problem is that if values[0] && values[1] the query would not return anything if values[0] was greater than values[1].




回答2:


For our advanced searching we create a filter object which encapsulates the activerecord queries into simple methods. It was originally based on this Thoughtbot post

A book filter could look something like this:

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)



回答3:


Take a look at the ransack gem, which is the successor to the meta_search gem, which still seems to have the better documentation.

If you do want to roll your own, there's nothing preventing you from chaining clauses using the same attribute:

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

But it's really not necessary to roll your own search, there are plenty of ready solutions available as in the gems above.



来源:https://stackoverflow.com/questions/9308820/rails-searching-with-multiple-conditions-if-values-are-not-empty

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!